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  }