launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/state/apiserver/upgrader/upgrader.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package upgrader 5 6 import ( 7 errgo "launchpad.net/errgo/errors" 8 9 "launchpad.net/juju-core/environs/config" 10 "launchpad.net/juju-core/errors" 11 "launchpad.net/juju-core/state" 12 "launchpad.net/juju-core/state/api/params" 13 "launchpad.net/juju-core/state/apiserver/common" 14 "launchpad.net/juju-core/state/watcher" 15 "launchpad.net/juju-core/version" 16 ) 17 18 var mask = errgo.Mask 19 20 // UpgraderAPI provides access to the Upgrader API facade. 21 type UpgraderAPI struct { 22 *common.ToolsGetter 23 24 st *state.State 25 resources *common.Resources 26 authorizer common.Authorizer 27 } 28 29 // NewUpgraderAPI creates a new client-side UpgraderAPI facade. 30 func NewUpgraderAPI( 31 st *state.State, 32 resources *common.Resources, 33 authorizer common.Authorizer, 34 ) (*UpgraderAPI, error) { 35 if !authorizer.AuthMachineAgent() && !authorizer.AuthUnitAgent() { 36 return nil, common.ErrPerm 37 } 38 getCanRead := func() (common.AuthFunc, error) { 39 return authorizer.AuthOwner, nil 40 } 41 return &UpgraderAPI{ 42 ToolsGetter: common.NewToolsGetter(st, getCanRead), 43 st: st, 44 resources: resources, 45 authorizer: authorizer, 46 }, nil 47 } 48 49 // WatchAPIVersion starts a watcher to track if there is a new version 50 // of the API that we want to upgrade to 51 func (u *UpgraderAPI) WatchAPIVersion(args params.Entities) (params.NotifyWatchResults, error) { 52 result := params.NotifyWatchResults{ 53 Results: make([]params.NotifyWatchResult, len(args.Entities)), 54 } 55 for i, agent := range args.Entities { 56 err := common.ErrPerm 57 if u.authorizer.AuthOwner(agent.Tag) { 58 watch := u.st.WatchForEnvironConfigChanges() 59 // Consume the initial event. Technically, API 60 // calls to Watch 'transmit' the initial event 61 // in the Watch response. But NotifyWatchers 62 // have no state to transmit. 63 if _, ok := <-watch.Changes(); ok { 64 result.Results[i].NotifyWatcherId = u.resources.Register(watch) 65 err = nil 66 } else { 67 err = watcher.MustErr(watch) 68 } 69 } 70 result.Results[i].Error = common.ServerError(err) 71 } 72 return result, nil 73 } 74 75 func (u *UpgraderAPI) getGlobalAgentVersion() (version.Number, *config.Config, error) { 76 // Get the Agent Version requested in the Environment Config 77 cfg, err := u.st.EnvironConfig() 78 if err != nil { 79 return version.Number{}, nil, mask(err) 80 } 81 agentVersion, ok := cfg.AgentVersion() 82 if !ok { 83 return version.Number{}, nil, errgo.New("agent version not set in environment config") 84 } 85 return agentVersion, cfg, nil 86 } 87 88 // DesiredVersion reports the Agent Version that we want that agent to be running 89 func (u *UpgraderAPI) DesiredVersion(args params.Entities) (params.VersionResults, error) { 90 results := make([]params.VersionResult, len(args.Entities)) 91 if len(args.Entities) == 0 { 92 return params.VersionResults{}, nil 93 } 94 agentVersion, _, err := u.getGlobalAgentVersion() 95 if err != nil { 96 return params.VersionResults{}, common.ServerError(err) 97 } 98 for i, entity := range args.Entities { 99 err := common.ErrPerm 100 if u.authorizer.AuthOwner(entity.Tag) { 101 results[i].Version = &agentVersion 102 err = nil 103 } 104 results[i].Error = common.ServerError(err) 105 } 106 return params.VersionResults{results}, nil 107 } 108 109 // SetTools updates the recorded tools version for the agents. 110 func (u *UpgraderAPI) SetTools(args params.EntitiesVersion) (params.ErrorResults, error) { 111 results := params.ErrorResults{ 112 Results: make([]params.ErrorResult, len(args.AgentTools)), 113 } 114 for i, agentTools := range args.AgentTools { 115 err := u.setOneAgentVersion(agentTools.Tag, agentTools.Tools.Version) 116 results.Results[i].Error = common.ServerError(err) 117 } 118 return results, nil 119 } 120 121 func (u *UpgraderAPI) setOneAgentVersion(tag string, vers version.Binary) error { 122 if !u.authorizer.AuthOwner(tag) { 123 return common.ErrPerm 124 } 125 entity, err := u.findEntity(tag) 126 if err != nil { 127 return mask(err) 128 } 129 return entity.SetAgentVersion(vers) 130 } 131 132 func (u *UpgraderAPI) findEntity(tag string) (state.AgentTooler, error) { 133 entity0, err := u.st.FindEntity(tag) 134 if err != nil { 135 return nil, mask(err, errors.IsNotFoundError) 136 } 137 entity, ok := entity0.(state.AgentTooler) 138 if !ok { 139 return nil, common.NotSupportedError(tag, "agent tools") 140 } 141 return entity, nil 142 }