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  }