launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/state/apiserver/provisioner/provisioner.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package provisioner 5 6 import ( 7 errgo "launchpad.net/errgo/errors" 8 "launchpad.net/juju-core/constraints" 9 "launchpad.net/juju-core/errors" 10 "launchpad.net/juju-core/instance" 11 "launchpad.net/juju-core/names" 12 "launchpad.net/juju-core/state" 13 "launchpad.net/juju-core/state/api/params" 14 "launchpad.net/juju-core/state/apiserver/common" 15 "launchpad.net/juju-core/state/watcher" 16 ) 17 18 var mask = errgo.Mask 19 20 // ProvisionerAPI provides access to the Provisioner API facade. 21 type ProvisionerAPI struct { 22 *common.Remover 23 *common.StatusSetter 24 *common.DeadEnsurer 25 *common.PasswordChanger 26 *common.LifeGetter 27 *common.StateAddresser 28 *common.APIAddresser 29 *common.ToolsGetter 30 *common.EnvironWatcher 31 *common.EnvironMachinesWatcher 32 *common.InstanceIdGetter 33 34 st *state.State 35 resources *common.Resources 36 authorizer common.Authorizer 37 getAuthFunc common.GetAuthFunc 38 } 39 40 // NewProvisionerAPI creates a new server-side ProvisionerAPI facade. 41 func NewProvisionerAPI( 42 st *state.State, 43 resources *common.Resources, 44 authorizer common.Authorizer, 45 ) (*ProvisionerAPI, error) { 46 if !authorizer.AuthMachineAgent() && !authorizer.AuthEnvironManager() { 47 return nil, common.ErrPerm 48 } 49 getAuthFunc := func() (common.AuthFunc, error) { 50 isEnvironManager := authorizer.AuthEnvironManager() 51 isMachineAgent := authorizer.AuthMachineAgent() 52 authEntityTag := authorizer.GetAuthTag() 53 54 return func(tag string) bool { 55 if isMachineAgent && tag == authEntityTag { 56 // A machine agent can always access its own machine. 57 return true 58 } 59 _, id, err := names.ParseTag(tag, names.MachineTagKind) 60 if err != nil { 61 return false 62 } 63 parentId := state.ParentId(id) 64 if parentId == "" { 65 // All top-level machines are accessible by the 66 // environment manager. 67 return isEnvironManager 68 } 69 // All containers with the authenticated machine as a 70 // parent are accessible by it. 71 return isMachineAgent && names.MachineTag(parentId) == authEntityTag 72 }, nil 73 } 74 // Both provisioner types can watch the environment. 75 getCanWatch := common.AuthAlways(true) 76 // Only the environment provisioner can read secrets. 77 getCanReadSecrets := common.AuthAlways(authorizer.AuthEnvironManager()) 78 return &ProvisionerAPI{ 79 Remover: common.NewRemover(st, false, getAuthFunc), 80 StatusSetter: common.NewStatusSetter(st, getAuthFunc), 81 DeadEnsurer: common.NewDeadEnsurer(st, getAuthFunc), 82 PasswordChanger: common.NewPasswordChanger(st, getAuthFunc), 83 LifeGetter: common.NewLifeGetter(st, getAuthFunc), 84 StateAddresser: common.NewStateAddresser(st), 85 APIAddresser: common.NewAPIAddresser(st), 86 ToolsGetter: common.NewToolsGetter(st, getAuthFunc), 87 EnvironWatcher: common.NewEnvironWatcher(st, resources, getCanWatch, getCanReadSecrets), 88 EnvironMachinesWatcher: common.NewEnvironMachinesWatcher(st, resources, getCanReadSecrets), 89 InstanceIdGetter: common.NewInstanceIdGetter(st, getAuthFunc), 90 st: st, 91 resources: resources, 92 authorizer: authorizer, 93 getAuthFunc: getAuthFunc, 94 }, nil 95 } 96 97 func (p *ProvisionerAPI) getMachine(canAccess common.AuthFunc, tag string) (*state.Machine, error) { 98 if !canAccess(tag) { 99 return nil, common.ErrPerm 100 } 101 entity, err := p.st.FindEntity(tag) 102 if err != nil { 103 return nil, mask(err, errors.IsNotFoundError) 104 } 105 106 // The authorization function guarantees that the tag represents a 107 // machine. 108 return entity.(*state.Machine), nil 109 } 110 111 func (p *ProvisionerAPI) watchOneMachineContainers(arg params.WatchContainer) (params.StringsWatchResult, error) { 112 nothing := params.StringsWatchResult{} 113 canAccess, err := p.getAuthFunc() 114 if err != nil { 115 return nothing, mask(err) 116 } 117 if !canAccess(arg.MachineTag) { 118 return nothing, common.ErrPerm 119 } 120 _, id, err := names.ParseTag(arg.MachineTag, names.MachineTagKind) 121 if err != nil { 122 return nothing, mask(err) 123 } 124 machine, err := p.st.Machine(id) 125 if err != nil { 126 return nothing, mask(err, errors.IsNotFoundError) 127 } 128 var watch state.StringsWatcher 129 if arg.ContainerType != "" { 130 watch = machine.WatchContainers(instance.ContainerType(arg.ContainerType)) 131 } else { 132 watch = machine.WatchAllContainers() 133 } 134 // Consume the initial event and forward it to the result. 135 if changes, ok := <-watch.Changes(); ok { 136 return params.StringsWatchResult{ 137 StringsWatcherId: p.resources.Register(watch), 138 Changes: changes, 139 }, nil 140 } 141 return nothing, watcher.MustErr(watch) 142 } 143 144 // WatchContainers starts a StringsWatcher to watch containers deployed to 145 // any machine passed in args. 146 func (p *ProvisionerAPI) WatchContainers(args params.WatchContainers) (params.StringsWatchResults, error) { 147 result := params.StringsWatchResults{ 148 Results: make([]params.StringsWatchResult, len(args.Params)), 149 } 150 for i, arg := range args.Params { 151 watcherResult, err := p.watchOneMachineContainers(arg) 152 result.Results[i] = watcherResult 153 result.Results[i].Error = common.ServerError(err) 154 } 155 return result, nil 156 } 157 158 // WatchAllContainers starts a StringsWatcher to watch all containers deployed to 159 // any machine passed in args. 160 func (p *ProvisionerAPI) WatchAllContainers(args params.WatchContainers) (params.StringsWatchResults, error) { 161 return p.WatchContainers(args) 162 } 163 164 // SetSupportedContainers updates the list of containers supported by the machines passed in args. 165 func (p *ProvisionerAPI) SetSupportedContainers( 166 args params.MachineContainersParams) (params.ErrorResults, error) { 167 168 result := params.ErrorResults{ 169 Results: make([]params.ErrorResult, len(args.Params)), 170 } 171 for i, arg := range args.Params { 172 canAccess, err := p.getAuthFunc() 173 if err != nil { 174 return result, mask(err) 175 } 176 machine, err := p.getMachine(canAccess, arg.MachineTag) 177 if err != nil { 178 result.Results[i].Error = common.ServerError(err) 179 continue 180 } 181 if len(arg.ContainerTypes) == 0 { 182 err = machine.SupportsNoContainers() 183 } else { 184 err = machine.SetSupportedContainers(arg.ContainerTypes) 185 } 186 if err != nil { 187 result.Results[i].Error = common.ServerError(err) 188 } 189 } 190 return result, nil 191 } 192 193 // ContainerConfig returns information from the environment config that are 194 // needed for container cloud-init. 195 func (p *ProvisionerAPI) ContainerConfig() (params.ContainerConfig, error) { 196 result := params.ContainerConfig{} 197 config, err := p.st.EnvironConfig() 198 if err != nil { 199 return result, mask(err) 200 } 201 result.ProviderType = config.Type() 202 result.AuthorizedKeys = config.AuthorizedKeys() 203 result.SSLHostnameVerification = config.SSLHostnameVerification() 204 result.SyslogPort = config.SyslogPort() 205 result.Proxy = config.ProxySettings() 206 result.AptProxy = config.AptProxySettings() 207 return result, nil 208 } 209 210 // Status returns the status of each given machine entity. 211 func (p *ProvisionerAPI) Status(args params.Entities) (params.StatusResults, error) { 212 result := params.StatusResults{ 213 Results: make([]params.StatusResult, len(args.Entities)), 214 } 215 canAccess, err := p.getAuthFunc() 216 if err != nil { 217 return result, mask(err) 218 } 219 for i, entity := range args.Entities { 220 machine, err := p.getMachine(canAccess, entity.Tag) 221 if err == nil { 222 r := &result.Results[i] 223 r.Status, r.Info, _, err = machine.Status() 224 } 225 result.Results[i].Error = common.ServerError(err) 226 } 227 return result, nil 228 } 229 230 // Series returns the deployed series for each given machine entity. 231 func (p *ProvisionerAPI) Series(args params.Entities) (params.StringResults, error) { 232 result := params.StringResults{ 233 Results: make([]params.StringResult, len(args.Entities)), 234 } 235 canAccess, err := p.getAuthFunc() 236 if err != nil { 237 return result, mask(err) 238 } 239 for i, entity := range args.Entities { 240 machine, err := p.getMachine(canAccess, entity.Tag) 241 if err == nil { 242 result.Results[i].Result = machine.Series() 243 } 244 result.Results[i].Error = common.ServerError(err) 245 } 246 return result, nil 247 } 248 249 // Constraints returns the constraints for each given machine entity. 250 func (p *ProvisionerAPI) Constraints(args params.Entities) (params.ConstraintsResults, error) { 251 result := params.ConstraintsResults{ 252 Results: make([]params.ConstraintsResult, len(args.Entities)), 253 } 254 canAccess, err := p.getAuthFunc() 255 if err != nil { 256 return result, mask(err) 257 } 258 for i, entity := range args.Entities { 259 machine, err := p.getMachine(canAccess, entity.Tag) 260 if err == nil { 261 var cons constraints.Value 262 cons, err = machine.Constraints() 263 if err == nil { 264 result.Results[i].Constraints = cons 265 } 266 } 267 result.Results[i].Error = common.ServerError(err) 268 } 269 return result, nil 270 } 271 272 // SetProvisioned sets the provider specific machine id, nonce and 273 // metadata for each given machine. Once set, the instance id cannot 274 // be changed. 275 func (p *ProvisionerAPI) SetProvisioned(args params.SetProvisioned) (params.ErrorResults, error) { 276 result := params.ErrorResults{ 277 Results: make([]params.ErrorResult, len(args.Machines)), 278 } 279 canAccess, err := p.getAuthFunc() 280 if err != nil { 281 return result, mask(err) 282 } 283 for i, arg := range args.Machines { 284 machine, err := p.getMachine(canAccess, arg.Tag) 285 if err == nil { 286 err = machine.SetProvisioned(arg.InstanceId, arg.Nonce, arg.Characteristics) 287 } 288 result.Results[i].Error = common.ServerError(err) 289 } 290 return result, nil 291 }