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