github.com/cloudbase/juju-core@v0.0.0-20140504232958-a7271ac7912f/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 "errors" 8 9 "launchpad.net/juju-core/environs/config" 10 "launchpad.net/juju-core/state" 11 "launchpad.net/juju-core/state/api/params" 12 "launchpad.net/juju-core/state/apiserver/common" 13 "launchpad.net/juju-core/state/watcher" 14 "launchpad.net/juju-core/version" 15 ) 16 17 type Upgrader interface { 18 WatchAPIVersion(args params.Entities) (params.NotifyWatchResults, error) 19 DesiredVersion(args params.Entities) (params.VersionResults, error) 20 Tools(args params.Entities) (params.ToolsResults, error) 21 SetTools(args params.EntitiesVersion) (params.ErrorResults, error) 22 } 23 24 // UpgraderAPI provides access to the Upgrader API facade. 25 type UpgraderAPI struct { 26 *common.ToolsGetter 27 *common.ToolsSetter 28 29 st *state.State 30 resources *common.Resources 31 authorizer common.Authorizer 32 } 33 34 // NewUpgraderAPI creates a new client-side UpgraderAPI facade. 35 func NewUpgraderAPI( 36 st *state.State, 37 resources *common.Resources, 38 authorizer common.Authorizer, 39 ) (*UpgraderAPI, error) { 40 if !authorizer.AuthMachineAgent() { 41 return nil, common.ErrPerm 42 } 43 getCanReadWrite := func() (common.AuthFunc, error) { 44 return authorizer.AuthOwner, nil 45 } 46 return &UpgraderAPI{ 47 ToolsGetter: common.NewToolsGetter(st, getCanReadWrite), 48 ToolsSetter: common.NewToolsSetter(st, getCanReadWrite), 49 st: st, 50 resources: resources, 51 authorizer: authorizer, 52 }, nil 53 } 54 55 // WatchAPIVersion starts a watcher to track if there is a new version 56 // of the API that we want to upgrade to 57 func (u *UpgraderAPI) WatchAPIVersion(args params.Entities) (params.NotifyWatchResults, error) { 58 result := params.NotifyWatchResults{ 59 Results: make([]params.NotifyWatchResult, len(args.Entities)), 60 } 61 for i, agent := range args.Entities { 62 err := common.ErrPerm 63 if u.authorizer.AuthOwner(agent.Tag) { 64 watch := u.st.WatchForEnvironConfigChanges() 65 // Consume the initial event. Technically, API 66 // calls to Watch 'transmit' the initial event 67 // in the Watch response. But NotifyWatchers 68 // have no state to transmit. 69 if _, ok := <-watch.Changes(); ok { 70 result.Results[i].NotifyWatcherId = u.resources.Register(watch) 71 err = nil 72 } else { 73 err = watcher.MustErr(watch) 74 } 75 } 76 result.Results[i].Error = common.ServerError(err) 77 } 78 return result, nil 79 } 80 81 func (u *UpgraderAPI) getGlobalAgentVersion() (version.Number, *config.Config, error) { 82 // Get the Agent Version requested in the Environment Config 83 cfg, err := u.st.EnvironConfig() 84 if err != nil { 85 return version.Number{}, nil, err 86 } 87 agentVersion, ok := cfg.AgentVersion() 88 if !ok { 89 return version.Number{}, nil, errors.New("agent version not set in environment config") 90 } 91 return agentVersion, cfg, nil 92 } 93 94 // DesiredVersion reports the Agent Version that we want that agent to be running 95 func (u *UpgraderAPI) DesiredVersion(args params.Entities) (params.VersionResults, error) { 96 results := make([]params.VersionResult, len(args.Entities)) 97 if len(args.Entities) == 0 { 98 return params.VersionResults{}, nil 99 } 100 agentVersion, _, err := u.getGlobalAgentVersion() 101 if err != nil { 102 return params.VersionResults{}, common.ServerError(err) 103 } 104 for i, entity := range args.Entities { 105 err := common.ErrPerm 106 if u.authorizer.AuthOwner(entity.Tag) { 107 results[i].Version = &agentVersion 108 err = nil 109 } 110 results[i].Error = common.ServerError(err) 111 } 112 return params.VersionResults{results}, nil 113 }