github.com/cloudbase/juju-core@v0.0.0-20140504232958-a7271ac7912f/state/apiserver/charmrevisionupdater/updater.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package charmrevisionupdater 5 6 import ( 7 "github.com/juju/loggo" 8 9 "launchpad.net/juju-core/charm" 10 "launchpad.net/juju-core/log" 11 "launchpad.net/juju-core/state" 12 "launchpad.net/juju-core/state/api/params" 13 "launchpad.net/juju-core/state/apiserver/common" 14 ) 15 16 var logger = loggo.GetLogger("juju.state.apiserver.charmrevisionupdater") 17 18 // CharmRevisionUpdater defines the methods on the charmrevisionupdater API end point. 19 type CharmRevisionUpdater interface { 20 UpdateLatestRevisions() (params.ErrorResult, error) 21 } 22 23 // CharmRevisionUpdaterAPI implements the CharmRevisionUpdater interface and is the concrete 24 // implementation of the api end point. 25 type CharmRevisionUpdaterAPI struct { 26 state *state.State 27 resources *common.Resources 28 authorizer common.Authorizer 29 } 30 31 var _ CharmRevisionUpdater = (*CharmRevisionUpdaterAPI)(nil) 32 33 // NewCharmRevisionUpdaterAPI creates a new server-side charmrevisionupdater API end point. 34 func NewCharmRevisionUpdaterAPI( 35 st *state.State, 36 resources *common.Resources, 37 authorizer common.Authorizer, 38 ) (*CharmRevisionUpdaterAPI, error) { 39 if !authorizer.AuthMachineAgent() && !authorizer.AuthEnvironManager() { 40 return nil, common.ErrPerm 41 } 42 return &CharmRevisionUpdaterAPI{ 43 state: st, resources: resources, authorizer: authorizer}, nil 44 } 45 46 // UpdateLatestRevisions retrieves the latest revision information from the charm store for all deployed charms 47 // and records this information in state. 48 func (api *CharmRevisionUpdaterAPI) UpdateLatestRevisions() (params.ErrorResult, error) { 49 // First get the uuid for the environment to use when querying the charm store. 50 env, err := api.state.Environment() 51 if err != nil { 52 return params.ErrorResult{common.ServerError(err)}, nil 53 } 54 uuid := env.UUID() 55 56 deployedCharms, err := fetchAllDeployedCharms(api.state) 57 if err != nil { 58 return params.ErrorResult{common.ServerError(err)}, nil 59 } 60 // Look up the revision information for all the deployed charms. 61 curls, err := retrieveLatestCharmInfo(deployedCharms, uuid) 62 if err != nil { 63 return params.ErrorResult{common.ServerError(err)}, nil 64 } 65 // Add the charms and latest revision info to state as charm placeholders. 66 for _, curl := range curls { 67 if err = api.state.AddStoreCharmPlaceholder(curl); err != nil { 68 return params.ErrorResult{common.ServerError(err)}, nil 69 } 70 } 71 return params.ErrorResult{}, nil 72 } 73 74 // fetchAllServicesAndUnits returns a map from service name to service 75 // and a map from service name to unit name to unit. 76 func fetchAllDeployedCharms(st *state.State) (map[string]*charm.URL, error) { 77 deployedCharms := make(map[string]*charm.URL) 78 services, err := st.AllServices() 79 if err != nil { 80 return nil, err 81 } 82 for _, s := range services { 83 url, _ := s.CharmURL() 84 // Record the basic charm information so it can be bulk processed later to 85 // get the available revision numbers from the repo. 86 baseCharm := url.WithRevision(-1) 87 deployedCharms[baseCharm.String()] = baseCharm 88 } 89 return deployedCharms, nil 90 } 91 92 // retrieveLatestCharmInfo looks up the charm store to return the charm URLs for the 93 // latest revision of the deployed charms. 94 func retrieveLatestCharmInfo(deployedCharms map[string]*charm.URL, uuid string) ([]*charm.URL, error) { 95 var curls []*charm.URL 96 for _, curl := range deployedCharms { 97 if curl.Schema == "local" { 98 // Version checking for charms from local repositories is not 99 // currently supported, since we don't yet support passing in 100 // a path to the local repo. This may change if the need arises. 101 continue 102 } 103 curls = append(curls, curl) 104 } 105 106 // Do a bulk call to get the revision info for all charms. 107 logger.Infof("retrieving revision information for %d charms", len(curls)) 108 store := charm.Store.WithJujuAttrs("environment_uuid=" + uuid) 109 revInfo, err := store.Latest(curls...) 110 if err != nil { 111 return nil, log.LoggedErrorf(logger, "finding charm revision info: %v", err) 112 } 113 var latestCurls []*charm.URL 114 for i, info := range revInfo { 115 curl := curls[i] 116 if info.Err == nil { 117 latestCurls = append(latestCurls, curl.WithRevision(info.Revision)) 118 } else { 119 logger.Errorf("retrieving charm info for %s: %v", curl, info.Err) 120 } 121 } 122 return latestCurls, nil 123 }