github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/apiserver/machine/machiner.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 // The machiner package implements the API interface 5 // used by the machiner worker. 6 package machine 7 8 import ( 9 "github.com/juju/errors" 10 "github.com/juju/loggo" 11 "gopkg.in/juju/names.v2" 12 13 "github.com/juju/juju/apiserver/common" 14 "github.com/juju/juju/apiserver/common/networkingcommon" 15 "github.com/juju/juju/apiserver/facade" 16 "github.com/juju/juju/apiserver/params" 17 "github.com/juju/juju/state" 18 "github.com/juju/juju/state/multiwatcher" 19 "github.com/juju/juju/state/stateenvirons" 20 ) 21 22 var logger = loggo.GetLogger("juju.apiserver.machine") 23 24 func init() { 25 common.RegisterStandardFacade("Machiner", 1, NewMachinerAPI) 26 } 27 28 // MachinerAPI implements the API used by the machiner worker. 29 type MachinerAPI struct { 30 *common.LifeGetter 31 *common.StatusSetter 32 *common.DeadEnsurer 33 *common.AgentEntityWatcher 34 *common.APIAddresser 35 36 st *state.State 37 auth facade.Authorizer 38 getCanModify common.GetAuthFunc 39 getCanRead common.GetAuthFunc 40 } 41 42 // NewMachinerAPI creates a new instance of the Machiner API. 43 func NewMachinerAPI(st *state.State, resources facade.Resources, authorizer facade.Authorizer) (*MachinerAPI, error) { 44 if !authorizer.AuthMachineAgent() { 45 return nil, common.ErrPerm 46 } 47 getCanModify := func() (common.AuthFunc, error) { 48 return authorizer.AuthOwner, nil 49 } 50 getCanRead := func() (common.AuthFunc, error) { 51 return authorizer.AuthOwner, nil 52 } 53 return &MachinerAPI{ 54 LifeGetter: common.NewLifeGetter(st, getCanRead), 55 StatusSetter: common.NewStatusSetter(st, getCanModify), 56 DeadEnsurer: common.NewDeadEnsurer(st, getCanModify), 57 AgentEntityWatcher: common.NewAgentEntityWatcher(st, resources, getCanRead), 58 APIAddresser: common.NewAPIAddresser(st, resources), 59 st: st, 60 auth: authorizer, 61 getCanModify: getCanModify, 62 getCanRead: getCanRead, 63 }, nil 64 } 65 66 func (api *MachinerAPI) getMachine(tag names.Tag) (*state.Machine, error) { 67 entity, err := api.st.FindEntity(tag) 68 if err != nil { 69 return nil, err 70 } 71 return entity.(*state.Machine), nil 72 } 73 74 func (api *MachinerAPI) SetMachineAddresses(args params.SetMachinesAddresses) (params.ErrorResults, error) { 75 results := params.ErrorResults{ 76 Results: make([]params.ErrorResult, len(args.MachineAddresses)), 77 } 78 canModify, err := api.getCanModify() 79 if err != nil { 80 return results, err 81 } 82 for i, arg := range args.MachineAddresses { 83 tag, err := names.ParseMachineTag(arg.Tag) 84 if err != nil { 85 results.Results[i].Error = common.ServerError(common.ErrPerm) 86 continue 87 } 88 err = common.ErrPerm 89 if canModify(tag) { 90 var m *state.Machine 91 m, err = api.getMachine(tag) 92 if err == nil { 93 addresses := params.NetworkAddresses(arg.Addresses...) 94 err = m.SetMachineAddresses(addresses...) 95 } else if errors.IsNotFound(err) { 96 err = common.ErrPerm 97 } 98 } 99 results.Results[i].Error = common.ServerError(err) 100 } 101 return results, nil 102 } 103 104 // Jobs returns the jobs assigned to the given entities. 105 func (api *MachinerAPI) Jobs(args params.Entities) (params.JobsResults, error) { 106 result := params.JobsResults{ 107 Results: make([]params.JobsResult, len(args.Entities)), 108 } 109 110 canRead, err := api.getCanRead() 111 if err != nil { 112 return result, err 113 } 114 115 for i, agent := range args.Entities { 116 tag, err := names.ParseMachineTag(agent.Tag) 117 if err != nil { 118 result.Results[i].Error = common.ServerError(err) 119 continue 120 } 121 122 if !canRead(tag) { 123 result.Results[i].Error = common.ServerError(common.ErrPerm) 124 continue 125 } 126 127 machine, err := api.getMachine(tag) 128 if err != nil { 129 result.Results[i].Error = common.ServerError(err) 130 continue 131 } 132 machineJobs := machine.Jobs() 133 jobs := make([]multiwatcher.MachineJob, len(machineJobs)) 134 for i, job := range machineJobs { 135 jobs[i] = job.ToParams() 136 } 137 result.Results[i].Jobs = jobs 138 } 139 return result, nil 140 } 141 142 func (api *MachinerAPI) SetObservedNetworkConfig(args params.SetMachineNetworkConfig) error { 143 m, err := api.getMachineForSettingNetworkConfig(args.Tag) 144 if err != nil { 145 return errors.Trace(err) 146 } 147 if m.IsContainer() { 148 return nil 149 } 150 observedConfig := args.Config 151 logger.Tracef("observed network config of machine %q: %+v", m.Id(), observedConfig) 152 if len(observedConfig) == 0 { 153 logger.Infof("not updating machine network config: no observed network config found") 154 return nil 155 } 156 157 providerConfig, err := api.getOneMachineProviderNetworkConfig(m) 158 if errors.IsNotProvisioned(err) { 159 logger.Infof("not updating provider network config: %v", err) 160 return nil 161 } 162 if err != nil { 163 return errors.Trace(err) 164 } 165 if len(providerConfig) == 0 { 166 logger.Infof("not updating machine network config: no provider network config found") 167 return nil 168 } 169 170 mergedConfig := networkingcommon.MergeProviderAndObservedNetworkConfigs(providerConfig, observedConfig) 171 logger.Tracef("merged observed and provider network config: %+v", mergedConfig) 172 173 return api.setOneMachineNetworkConfig(m, mergedConfig) 174 } 175 176 func (api *MachinerAPI) getMachineForSettingNetworkConfig(machineTag string) (*state.Machine, error) { 177 canModify, err := api.getCanModify() 178 if err != nil { 179 return nil, errors.Trace(err) 180 } 181 182 tag, err := names.ParseMachineTag(machineTag) 183 if err != nil { 184 return nil, errors.Trace(err) 185 } 186 if !canModify(tag) { 187 return nil, errors.Trace(common.ErrPerm) 188 } 189 190 m, err := api.getMachine(tag) 191 if errors.IsNotFound(err) { 192 return nil, errors.Trace(common.ErrPerm) 193 } else if err != nil { 194 return nil, errors.Trace(err) 195 } 196 197 if m.IsContainer() { 198 logger.Warningf("not updating network config for container %q", m.Id()) 199 } 200 201 return m, nil 202 } 203 204 func (api *MachinerAPI) setOneMachineNetworkConfig(m *state.Machine, networkConfig []params.NetworkConfig) error { 205 devicesArgs, devicesAddrs := networkingcommon.NetworkConfigsToStateArgs(networkConfig) 206 207 logger.Debugf("setting devices: %+v", devicesArgs) 208 if err := m.SetParentLinkLayerDevicesBeforeTheirChildren(devicesArgs); err != nil { 209 return errors.Trace(err) 210 } 211 212 logger.Debugf("setting addresses: %+v", devicesAddrs) 213 if err := m.SetDevicesAddressesIdempotently(devicesAddrs); err != nil { 214 return errors.Trace(err) 215 } 216 217 logger.Debugf("updated machine %q network config", m.Id()) 218 return nil 219 } 220 221 func (api *MachinerAPI) SetProviderNetworkConfig(args params.Entities) (params.ErrorResults, error) { 222 result := params.ErrorResults{ 223 Results: make([]params.ErrorResult, len(args.Entities)), 224 } 225 226 for i, arg := range args.Entities { 227 m, err := api.getMachineForSettingNetworkConfig(arg.Tag) 228 if err != nil { 229 result.Results[i].Error = common.ServerError(err) 230 continue 231 } 232 233 if m.IsContainer() { 234 continue 235 } 236 237 providerConfig, err := api.getOneMachineProviderNetworkConfig(m) 238 if err != nil { 239 result.Results[i].Error = common.ServerError(err) 240 continue 241 } else if len(providerConfig) == 0 { 242 continue 243 } 244 245 logger.Tracef("provider network config for %q: %+v", m.Id(), providerConfig) 246 247 if err := api.setOneMachineNetworkConfig(m, providerConfig); err != nil { 248 result.Results[i].Error = common.ServerError(err) 249 continue 250 } 251 } 252 return result, nil 253 } 254 255 func (api *MachinerAPI) getOneMachineProviderNetworkConfig(m *state.Machine) ([]params.NetworkConfig, error) { 256 instId, err := m.InstanceId() 257 if err != nil { 258 return nil, errors.Trace(err) 259 } 260 261 netEnviron, err := networkingcommon.NetworkingEnvironFromModelConfig( 262 stateenvirons.EnvironConfigGetter{api.st}, 263 ) 264 if errors.IsNotSupported(err) { 265 logger.Infof("not updating provider network config: %v", err) 266 return nil, nil 267 } else if err != nil { 268 return nil, errors.Annotate(err, "cannot get provider network config") 269 } 270 271 interfaceInfos, err := netEnviron.NetworkInterfaces(instId) 272 if err != nil { 273 return nil, errors.Annotatef(err, "cannot get network interfaces of %q", instId) 274 } 275 if len(interfaceInfos) == 0 { 276 logger.Infof("not updating provider network config: no interfaces returned") 277 return nil, nil 278 } 279 280 providerConfig := networkingcommon.NetworkConfigFromInterfaceInfo(interfaceInfos) 281 logger.Tracef("provider network config instance %q: %+v", instId, providerConfig) 282 283 return providerConfig, nil 284 }