github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/apiserver/upgrader/unitupgrader.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 "github.com/juju/names" 8 9 "github.com/juju/juju/apiserver/common" 10 "github.com/juju/juju/apiserver/params" 11 "github.com/juju/juju/state" 12 "github.com/juju/juju/state/watcher" 13 "github.com/juju/juju/version" 14 ) 15 16 // UnitUpgraderAPI provides access to the UnitUpgrader API facade. 17 type UnitUpgraderAPI struct { 18 *common.ToolsSetter 19 20 st *state.State 21 resources *common.Resources 22 authorizer common.Authorizer 23 } 24 25 // NewUnitUpgraderAPI creates a new server-side UnitUpgraderAPI facade. 26 func NewUnitUpgraderAPI( 27 st *state.State, 28 resources *common.Resources, 29 authorizer common.Authorizer, 30 ) (*UnitUpgraderAPI, error) { 31 if !authorizer.AuthUnitAgent() { 32 return nil, common.ErrPerm 33 } 34 35 getCanWrite := func() (common.AuthFunc, error) { 36 return authorizer.AuthOwner, nil 37 } 38 return &UnitUpgraderAPI{ 39 ToolsSetter: common.NewToolsSetter(st, getCanWrite), 40 st: st, 41 resources: resources, 42 authorizer: authorizer, 43 }, nil 44 } 45 46 func (u *UnitUpgraderAPI) watchAssignedMachine(unitTag names.Tag) (string, error) { 47 machine, err := u.getAssignedMachine(unitTag) 48 if err != nil { 49 return "", err 50 } 51 watch := machine.Watch() 52 // Consume the initial event. Technically, API 53 // calls to Watch 'transmit' the initial event 54 // in the Watch response. But NotifyWatchers 55 // have no state to transmit. 56 if _, ok := <-watch.Changes(); ok { 57 return u.resources.Register(watch), nil 58 } 59 return "", watcher.EnsureErr(watch) 60 } 61 62 // WatchAPIVersion starts a watcher to track if there is a new version 63 // of the API that we want to upgrade to. The watcher tracks changes to 64 // the unit's assigned machine since that's where the required agent version is stored. 65 func (u *UnitUpgraderAPI) WatchAPIVersion(args params.Entities) (params.NotifyWatchResults, error) { 66 result := params.NotifyWatchResults{ 67 Results: make([]params.NotifyWatchResult, len(args.Entities)), 68 } 69 for i, agent := range args.Entities { 70 tag, err := names.ParseTag(agent.Tag) 71 if err != nil { 72 result.Results[i].Error = common.ServerError(common.ErrPerm) 73 continue 74 } 75 err = common.ErrPerm 76 if u.authorizer.AuthOwner(tag) { 77 var watcherId string 78 watcherId, err = u.watchAssignedMachine(tag) 79 if err == nil { 80 result.Results[i].NotifyWatcherId = watcherId 81 } 82 } 83 result.Results[i].Error = common.ServerError(err) 84 } 85 return result, nil 86 } 87 88 // DesiredVersion reports the Agent Version that we want that unit to be running. 89 // The desired version is what the unit's assigned machine is running. 90 func (u *UnitUpgraderAPI) DesiredVersion(args params.Entities) (params.VersionResults, error) { 91 result := make([]params.VersionResult, len(args.Entities)) 92 for i, entity := range args.Entities { 93 tag, err := names.ParseTag(entity.Tag) 94 if err != nil { 95 result[i].Error = common.ServerError(common.ErrPerm) 96 continue 97 } 98 err = common.ErrPerm 99 if u.authorizer.AuthOwner(tag) { 100 result[i].Version, err = u.getMachineToolsVersion(tag) 101 } 102 result[i].Error = common.ServerError(err) 103 } 104 return params.VersionResults{Results: result}, nil 105 } 106 107 // Tools finds the tools necessary for the given agents. 108 func (u *UnitUpgraderAPI) Tools(args params.Entities) (params.ToolsResults, error) { 109 result := params.ToolsResults{ 110 Results: make([]params.ToolsResult, len(args.Entities)), 111 } 112 for i, entity := range args.Entities { 113 result.Results[i].Error = common.ServerError(common.ErrPerm) 114 tag, err := names.ParseTag(entity.Tag) 115 if err != nil { 116 continue 117 } 118 if u.authorizer.AuthOwner(tag) { 119 result.Results[i] = u.getMachineTools(tag) 120 } 121 } 122 return result, nil 123 } 124 125 func (u *UnitUpgraderAPI) getAssignedMachine(tag names.Tag) (*state.Machine, error) { 126 // Check that we really have a unit tag. 127 switch tag := tag.(type) { 128 case names.UnitTag: 129 unit, err := u.st.Unit(tag.Id()) 130 if err != nil { 131 return nil, common.ErrPerm 132 } 133 id, err := unit.AssignedMachineId() 134 if err != nil { 135 return nil, err 136 } 137 return u.st.Machine(id) 138 default: 139 return nil, common.ErrPerm 140 } 141 } 142 143 func (u *UnitUpgraderAPI) getMachineTools(tag names.Tag) params.ToolsResult { 144 var result params.ToolsResult 145 machine, err := u.getAssignedMachine(tag) 146 if err != nil { 147 result.Error = common.ServerError(err) 148 return result 149 } 150 machineTools, err := machine.AgentTools() 151 if err != nil { 152 result.Error = common.ServerError(err) 153 return result 154 } 155 result.Tools = machineTools 156 return result 157 } 158 159 func (u *UnitUpgraderAPI) getMachineToolsVersion(tag names.Tag) (*version.Number, error) { 160 machine, err := u.getAssignedMachine(tag) 161 if err != nil { 162 return nil, err 163 } 164 machineTools, err := machine.AgentTools() 165 if err != nil { 166 return nil, err 167 } 168 return &machineTools.Version.Number, nil 169 }