github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/apiserver/facades/agent/uniter/lxdprofile.go (about) 1 // Copyright 2018 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package uniter 5 6 import ( 7 "github.com/juju/errors" 8 "github.com/juju/loggo" 9 names "gopkg.in/juju/names.v2" 10 11 "github.com/juju/juju/apiserver/common" 12 "github.com/juju/juju/apiserver/facade" 13 "github.com/juju/juju/apiserver/params" 14 "github.com/juju/juju/state" 15 "github.com/juju/juju/state/watcher" 16 ) 17 18 //go:generate mockgen -package mocks -destination mocks/lxdprofile.go github.com/juju/juju/apiserver/facades/agent/uniter LXDProfileBackend,LXDProfileMachine,LXDProfileUnit 19 20 type LXDProfileBackend interface { 21 Machine(string) (LXDProfileMachine, error) 22 Unit(string) (LXDProfileUnit, error) 23 } 24 25 // LXDProfileMachine describes machine-receiver state methods 26 // for executing a lxd profile upgrade. 27 type LXDProfileMachine interface { 28 WatchLXDProfileUpgradeNotifications(string) (state.StringsWatcher, error) 29 Units() ([]LXDProfileUnit, error) 30 RemoveUpgradeCharmProfileData() error 31 } 32 33 // LXDProfileUnit describes unit-receiver state methods 34 // for executing a lxd profile upgrade. 35 type LXDProfileUnit interface { 36 Tag() names.Tag 37 AssignedMachineId() (string, error) 38 } 39 40 type LXDProfileAPI struct { 41 backend LXDProfileBackend 42 resources facade.Resources 43 44 logger loggo.Logger 45 46 accessUnitOrMachine common.GetAuthFunc 47 AccessMachine common.GetAuthFunc 48 accessUnit common.GetAuthFunc 49 } 50 51 // NewLXDProfileAPI returns a new LXDProfileAPI. Currently both 52 // GetAuthFuncs can used to determine current permissions. 53 func NewLXDProfileAPI( 54 backend LXDProfileBackend, 55 resources facade.Resources, 56 authorizer facade.Authorizer, 57 accessMachine common.GetAuthFunc, 58 accessUnit common.GetAuthFunc, 59 logger loggo.Logger, 60 ) *LXDProfileAPI { 61 logger.Tracef("NewLXDProfileAPI called with %s", authorizer.GetAuthTag()) 62 return &LXDProfileAPI{ 63 backend: backend, 64 resources: resources, 65 accessUnitOrMachine: common.AuthAny(accessUnit, accessMachine), 66 AccessMachine: accessMachine, 67 accessUnit: accessUnit, 68 logger: logger, 69 } 70 } 71 72 // LXDProfileState implements the LXDProfileBackend indirection 73 // over state.State. 74 type LXDProfileState struct { 75 st *state.State 76 } 77 78 func (s LXDProfileState) Machine(id string) (LXDProfileMachine, error) { 79 m, err := s.st.Machine(id) 80 return &lxdProfileMachine{m}, err 81 } 82 83 func (s LXDProfileState) Unit(id string) (LXDProfileUnit, error) { 84 return s.st.Unit(id) 85 } 86 87 type lxdProfileMachine struct { 88 *state.Machine 89 } 90 91 // Units maintains the LXDProfileMachine indirection by wrapping the call to 92 // state.Machine.Units(). 93 func (m *lxdProfileMachine) Units() ([]LXDProfileUnit, error) { 94 units, err := m.Machine.Units() 95 if err != nil { 96 return nil, errors.Trace(err) 97 } 98 99 wrapped := make([]LXDProfileUnit, len(units)) 100 for i, u := range units { 101 wrapped[i] = u 102 } 103 return wrapped, nil 104 } 105 106 // NewExternalLXDProfileAPI can be used for API registration. 107 func NewExternalLXDProfileAPI( 108 st *state.State, 109 resources facade.Resources, 110 authorizer facade.Authorizer, 111 accessMachine common.GetAuthFunc, 112 accessUnit common.GetAuthFunc, 113 logger loggo.Logger, 114 ) *LXDProfileAPI { 115 return NewLXDProfileAPI( 116 LXDProfileState{st}, 117 resources, 118 authorizer, 119 accessMachine, accessUnit, 120 logger, 121 ) 122 } 123 124 // WatchLXDProfileUpgradeNotifications returns a StringsWatcher for observing 125 // changes to the lxd profile changes. 126 func (u *LXDProfileAPI) WatchLXDProfileUpgradeNotifications(args params.LXDProfileUpgrade) (params.StringsWatchResults, error) { 127 u.logger.Tracef("Starting WatchLXDProfileUpgradeNotifications with %+v", args) 128 result := params.StringsWatchResults{ 129 Results: make([]params.StringsWatchResult, len(args.Entities)), 130 } 131 canAccess, err := u.accessUnitOrMachine() 132 if err != nil { 133 return params.StringsWatchResults{}, err 134 } 135 for i, entity := range args.Entities { 136 tag, err := names.ParseTag(entity.Tag) 137 if err != nil { 138 result.Results[i].Error = common.ServerError(common.ErrPerm) 139 continue 140 } 141 142 if !canAccess(tag) { 143 result.Results[i].Error = common.ServerError(common.ErrPerm) 144 continue 145 } 146 machine, err := u.getMachine(tag) 147 if err != nil { 148 result.Results[i].Error = common.ServerError(err) 149 continue 150 } 151 152 watcherId, initial, err := u.watchOneChangeLXDProfileUpgradeNotifications(machine, args.ApplicationName) 153 if err != nil { 154 result.Results[i].Error = common.ServerError(err) 155 continue 156 } 157 158 result.Results[i].StringsWatcherId = watcherId 159 result.Results[i].Changes = initial 160 } 161 return result, nil 162 } 163 164 func (u *LXDProfileAPI) watchOneChangeLXDProfileUpgradeNotifications(machine LXDProfileMachine, applicationName string) (string, []string, error) { 165 watch, err := machine.WatchLXDProfileUpgradeNotifications(applicationName) 166 if err != nil { 167 return "", nil, errors.Trace(err) 168 } 169 170 if changes, ok := <-watch.Changes(); ok { 171 return u.resources.Register(watch), changes, nil 172 } 173 return "", nil, watcher.EnsureErr(watch) 174 } 175 176 // RemoveUpgradeCharmProfileData is intended to clean up the LXDProfile status 177 // to ensure that we start from a clean slate. 178 func (u *LXDProfileAPI) RemoveUpgradeCharmProfileData(args params.Entities) (params.ErrorResults, error) { 179 u.logger.Tracef("Starting RemoveUpgradeCharmProfileData with %+v", args) 180 result := params.ErrorResults{ 181 Results: make([]params.ErrorResult, len(args.Entities)), 182 } 183 canAccess, err := u.accessUnitOrMachine() 184 if err != nil { 185 return params.ErrorResults{}, err 186 } 187 for i, entity := range args.Entities { 188 tag, err := names.ParseTag(entity.Tag) 189 if err != nil { 190 result.Results[i].Error = common.ServerError(common.ErrPerm) 191 continue 192 } 193 194 if !canAccess(tag) { 195 result.Results[i].Error = common.ServerError(common.ErrPerm) 196 continue 197 } 198 machine, err := u.getMachine(tag) 199 if err != nil { 200 result.Results[i].Error = common.ServerError(err) 201 continue 202 } 203 err = machine.RemoveUpgradeCharmProfileData() 204 if err != nil { 205 result.Results[i].Error = common.ServerError(err) 206 continue 207 } 208 } 209 return result, nil 210 } 211 212 func (u *LXDProfileAPI) getMachine(tag names.Tag) (LXDProfileMachine, error) { 213 var id string 214 switch tag.Kind() { 215 case names.MachineTagKind: 216 id = tag.Id() 217 case names.UnitTagKind: 218 unit, err := u.backend.Unit(tag.Id()) 219 if err != nil { 220 221 } 222 id, err = unit.AssignedMachineId() 223 if err != nil { 224 return nil, err 225 } 226 default: 227 } 228 return u.backend.Machine(id) 229 } 230 231 func (u *LXDProfileAPI) getUnit(tag names.Tag) (LXDProfileUnit, error) { 232 return u.backend.Unit(tag.Id()) 233 }