github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/apiserver/facades/controller/machineundertaker/undertaker.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package machineundertaker 5 6 import ( 7 "github.com/juju/errors" 8 "github.com/juju/loggo" 9 "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/network" 15 "github.com/juju/juju/state" 16 "github.com/juju/juju/state/watcher" 17 ) 18 19 var logger = loggo.GetLogger("juju.apiserver.machineundertaker") 20 21 // API implements the API facade used by the machine undertaker. 22 type API struct { 23 backend Backend 24 resources facade.Resources 25 canManageModel func(modelUUID string) bool 26 } 27 28 // NewAPI implements the API used by the machine undertaker worker to 29 // find out what provider-level resources need to be cleaned up when a 30 // machine goes away. 31 func NewAPI(backend Backend, resources facade.Resources, authorizer facade.Authorizer) (*API, error) { 32 if !authorizer.AuthController() { 33 return nil, errors.Trace(common.ErrPerm) 34 } 35 36 api := &API{ 37 backend: backend, 38 resources: resources, 39 canManageModel: func(modelUUID string) bool { 40 return modelUUID == authorizer.ConnectedModel() 41 }, 42 } 43 return api, nil 44 } 45 46 // NewFacade provides the signature required for facade registration. 47 func NewFacade(st *state.State, res facade.Resources, auth facade.Authorizer) (*API, error) { 48 return NewAPI(&backendShim{st}, res, auth) 49 } 50 51 // AllMachineRemovals returns tags for all of the machines that have 52 // been marked for removal in the requested model. 53 func (m *API) AllMachineRemovals(models params.Entities) params.EntitiesResults { 54 results := make([]params.EntitiesResult, len(models.Entities)) 55 for i, entity := range models.Entities { 56 entities, err := m.allRemovalsForTag(entity.Tag) 57 results[i].Entities = entities 58 results[i].Error = common.ServerError(err) 59 } 60 return params.EntitiesResults{Results: results} 61 } 62 63 func (m *API) allRemovalsForTag(tag string) ([]params.Entity, error) { 64 err := m.checkModelAuthorization(tag) 65 if err != nil { 66 return nil, errors.Trace(err) 67 } 68 machineIds, err := m.backend.AllMachineRemovals() 69 if err != nil { 70 return nil, errors.Trace(err) 71 } 72 var entities []params.Entity 73 for _, id := range machineIds { 74 entities = append(entities, params.Entity{ 75 Tag: names.NewMachineTag(id).String(), 76 }) 77 } 78 return entities, nil 79 } 80 81 // GetMachineProviderInterfaceInfo returns the provider details for 82 // all network interfaces attached to the machines requested. 83 func (m *API) GetMachineProviderInterfaceInfo(machines params.Entities) params.ProviderInterfaceInfoResults { 84 results := make([]params.ProviderInterfaceInfoResult, len(machines.Entities)) 85 for i, entity := range machines.Entities { 86 results[i].MachineTag = entity.Tag 87 88 interfaces, err := m.getInterfaceInfoForOneMachine(entity.Tag) 89 if err != nil { 90 results[i].Error = common.ServerError(err) 91 continue 92 } 93 94 infos := make([]params.ProviderInterfaceInfo, len(interfaces)) 95 for i, info := range interfaces { 96 infos[i].InterfaceName = info.InterfaceName 97 infos[i].MACAddress = info.MACAddress 98 infos[i].ProviderId = string(info.ProviderId) 99 } 100 101 results[i].Interfaces = infos 102 } 103 return params.ProviderInterfaceInfoResults{results} 104 } 105 106 func (m *API) getInterfaceInfoForOneMachine(machineTag string) ([]network.ProviderInterfaceInfo, error) { 107 tag, err := names.ParseMachineTag(machineTag) 108 if err != nil { 109 return nil, errors.Trace(err) 110 } 111 machine, err := m.backend.Machine(tag.Id()) 112 if err != nil { 113 return nil, errors.Trace(err) 114 } 115 interfaces, err := machine.AllProviderInterfaceInfos() 116 if err != nil { 117 return nil, errors.Trace(err) 118 } 119 return interfaces, nil 120 } 121 122 // CompleteMachineRemovals removes the specified machines from the 123 // model database. It should only be called once any provider-level 124 // cleanup has been done for those machines. 125 func (m *API) CompleteMachineRemovals(machines params.Entities) error { 126 machineIDs, err := collectMachineIDs(machines) 127 if err != nil { 128 return errors.Trace(err) 129 } 130 return m.backend.CompleteMachineRemovals(machineIDs...) 131 } 132 133 // WatchMachineRemovals returns a watcher that will signal each time a 134 // machine is marked for removal. 135 func (m *API) WatchMachineRemovals(models params.Entities) params.NotifyWatchResults { 136 results := make([]params.NotifyWatchResult, len(models.Entities)) 137 for i, entity := range models.Entities { 138 id, err := m.watchRemovalsForTag(entity.Tag) 139 results[i].NotifyWatcherId = id 140 results[i].Error = common.ServerError(err) 141 } 142 return params.NotifyWatchResults{Results: results} 143 } 144 145 func (m *API) watchRemovalsForTag(tag string) (string, error) { 146 err := m.checkModelAuthorization(tag) 147 if err != nil { 148 return "", errors.Trace(err) 149 } 150 watch := m.backend.WatchMachineRemovals() 151 if _, ok := <-watch.Changes(); ok { 152 return m.resources.Register(watch), nil 153 } else { 154 return "", watcher.EnsureErr(watch) 155 } 156 } 157 158 func (m *API) checkModelAuthorization(tag string) error { 159 modelTag, err := names.ParseModelTag(tag) 160 if err != nil { 161 return errors.Trace(err) 162 } 163 if !m.canManageModel(modelTag.Id()) { 164 return errors.Trace(common.ErrPerm) 165 } 166 return nil 167 } 168 169 func collectMachineIDs(args params.Entities) ([]string, error) { 170 machineIDs := make([]string, len(args.Entities)) 171 for i := range args.Entities { 172 tag, err := names.ParseMachineTag(args.Entities[i].Tag) 173 if err != nil { 174 return nil, errors.Trace(err) 175 } 176 machineIDs[i] = tag.Id() 177 } 178 return machineIDs, nil 179 }