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  }