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