github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/apiserver/provisioner/provisioner.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package provisioner
     5  
     6  import (
     7  	"time"
     8  
     9  	"github.com/juju/errors"
    10  	"github.com/juju/loggo"
    11  	"github.com/juju/utils/set"
    12  	"gopkg.in/juju/names.v2"
    13  
    14  	"github.com/juju/juju/apiserver/common"
    15  	"github.com/juju/juju/apiserver/common/networkingcommon"
    16  	"github.com/juju/juju/apiserver/common/storagecommon"
    17  	"github.com/juju/juju/apiserver/facade"
    18  	"github.com/juju/juju/apiserver/params"
    19  	"github.com/juju/juju/constraints"
    20  	"github.com/juju/juju/container"
    21  	"github.com/juju/juju/environs"
    22  	"github.com/juju/juju/instance"
    23  	"github.com/juju/juju/network"
    24  	"github.com/juju/juju/state"
    25  	"github.com/juju/juju/state/stateenvirons"
    26  	"github.com/juju/juju/state/watcher"
    27  	"github.com/juju/juju/status"
    28  	"github.com/juju/juju/storage"
    29  	"github.com/juju/juju/storage/poolmanager"
    30  )
    31  
    32  var logger = loggo.GetLogger("juju.apiserver.provisioner")
    33  
    34  func init() {
    35  	common.RegisterStandardFacade("Provisioner", 3, NewProvisionerAPI)
    36  }
    37  
    38  // ProvisionerAPI provides access to the Provisioner API facade.
    39  type ProvisionerAPI struct {
    40  	*common.ControllerConfigAPI
    41  	*common.Remover
    42  	*common.StatusSetter
    43  	*common.StatusGetter
    44  	*common.DeadEnsurer
    45  	*common.PasswordChanger
    46  	*common.LifeGetter
    47  	*common.StateAddresser
    48  	*common.APIAddresser
    49  	*common.ModelWatcher
    50  	*common.ModelMachinesWatcher
    51  	*common.InstanceIdGetter
    52  	*common.ToolsFinder
    53  	*common.ToolsGetter
    54  
    55  	st                      *state.State
    56  	resources               facade.Resources
    57  	authorizer              facade.Authorizer
    58  	storageProviderRegistry storage.ProviderRegistry
    59  	storagePoolManager      poolmanager.PoolManager
    60  	configGetter            environs.EnvironConfigGetter
    61  	getAuthFunc             common.GetAuthFunc
    62  }
    63  
    64  // NewProvisionerAPI creates a new server-side ProvisionerAPI facade.
    65  func NewProvisionerAPI(st *state.State, resources facade.Resources, authorizer facade.Authorizer) (*ProvisionerAPI, error) {
    66  	if !authorizer.AuthMachineAgent() && !authorizer.AuthModelManager() {
    67  		return nil, common.ErrPerm
    68  	}
    69  	getAuthFunc := func() (common.AuthFunc, error) {
    70  		isModelManager := authorizer.AuthModelManager()
    71  		isMachineAgent := authorizer.AuthMachineAgent()
    72  		authEntityTag := authorizer.GetAuthTag()
    73  
    74  		return func(tag names.Tag) bool {
    75  			if isMachineAgent && tag == authEntityTag {
    76  				// A machine agent can always access its own machine.
    77  				return true
    78  			}
    79  			switch tag := tag.(type) {
    80  			case names.MachineTag:
    81  				parentId := state.ParentId(tag.Id())
    82  				if parentId == "" {
    83  					// All top-level machines are accessible by the
    84  					// environment manager.
    85  					return isModelManager
    86  				}
    87  				// All containers with the authenticated machine as a
    88  				// parent are accessible by it.
    89  				// TODO(dfc) sometimes authEntity tag is nil, which is fine because nil is
    90  				// only equal to nil, but it suggests someone is passing an authorizer
    91  				// with a nil tag.
    92  				return isMachineAgent && names.NewMachineTag(parentId) == authEntityTag
    93  			default:
    94  				return false
    95  			}
    96  		}, nil
    97  	}
    98  	getAuthOwner := func() (common.AuthFunc, error) {
    99  		return authorizer.AuthOwner, nil
   100  	}
   101  	model, err := st.Model()
   102  	if err != nil {
   103  		return nil, err
   104  	}
   105  	configGetter := stateenvirons.EnvironConfigGetter{st}
   106  	env, err := environs.GetEnviron(configGetter, environs.New)
   107  	if err != nil {
   108  		return nil, err
   109  	}
   110  	urlGetter := common.NewToolsURLGetter(model.UUID(), st)
   111  	storageProviderRegistry := stateenvirons.NewStorageProviderRegistry(env)
   112  	return &ProvisionerAPI{
   113  		Remover:                 common.NewRemover(st, false, getAuthFunc),
   114  		StatusSetter:            common.NewStatusSetter(st, getAuthFunc),
   115  		StatusGetter:            common.NewStatusGetter(st, getAuthFunc),
   116  		DeadEnsurer:             common.NewDeadEnsurer(st, getAuthFunc),
   117  		PasswordChanger:         common.NewPasswordChanger(st, getAuthFunc),
   118  		LifeGetter:              common.NewLifeGetter(st, getAuthFunc),
   119  		StateAddresser:          common.NewStateAddresser(st),
   120  		APIAddresser:            common.NewAPIAddresser(st, resources),
   121  		ModelWatcher:            common.NewModelWatcher(st, resources, authorizer),
   122  		ModelMachinesWatcher:    common.NewModelMachinesWatcher(st, resources, authorizer),
   123  		ControllerConfigAPI:     common.NewControllerConfig(st),
   124  		InstanceIdGetter:        common.NewInstanceIdGetter(st, getAuthFunc),
   125  		ToolsFinder:             common.NewToolsFinder(configGetter, st, urlGetter),
   126  		ToolsGetter:             common.NewToolsGetter(st, configGetter, st, urlGetter, getAuthOwner),
   127  		st:                      st,
   128  		resources:               resources,
   129  		authorizer:              authorizer,
   130  		configGetter:            configGetter,
   131  		storageProviderRegistry: storageProviderRegistry,
   132  		storagePoolManager:      poolmanager.New(state.NewStateSettings(st), storageProviderRegistry),
   133  		getAuthFunc:             getAuthFunc,
   134  	}, nil
   135  }
   136  
   137  func (p *ProvisionerAPI) getMachine(canAccess common.AuthFunc, tag names.MachineTag) (*state.Machine, error) {
   138  	if !canAccess(tag) {
   139  		return nil, common.ErrPerm
   140  	}
   141  	entity, err := p.st.FindEntity(tag)
   142  	if err != nil {
   143  		return nil, err
   144  	}
   145  	// The authorization function guarantees that the tag represents a
   146  	// machine.
   147  	return entity.(*state.Machine), nil
   148  }
   149  
   150  func (p *ProvisionerAPI) watchOneMachineContainers(arg params.WatchContainer) (params.StringsWatchResult, error) {
   151  	nothing := params.StringsWatchResult{}
   152  	canAccess, err := p.getAuthFunc()
   153  	if err != nil {
   154  		return nothing, common.ErrPerm
   155  	}
   156  	tag, err := names.ParseMachineTag(arg.MachineTag)
   157  	if err != nil {
   158  		return nothing, common.ErrPerm
   159  	}
   160  	if !canAccess(tag) {
   161  		return nothing, common.ErrPerm
   162  	}
   163  	machine, err := p.st.Machine(tag.Id())
   164  	if err != nil {
   165  		return nothing, err
   166  	}
   167  	var watch state.StringsWatcher
   168  	if arg.ContainerType != "" {
   169  		watch = machine.WatchContainers(instance.ContainerType(arg.ContainerType))
   170  	} else {
   171  		watch = machine.WatchAllContainers()
   172  	}
   173  	// Consume the initial event and forward it to the result.
   174  	if changes, ok := <-watch.Changes(); ok {
   175  		return params.StringsWatchResult{
   176  			StringsWatcherId: p.resources.Register(watch),
   177  			Changes:          changes,
   178  		}, nil
   179  	}
   180  	return nothing, watcher.EnsureErr(watch)
   181  }
   182  
   183  // WatchContainers starts a StringsWatcher to watch containers deployed to
   184  // any machine passed in args.
   185  func (p *ProvisionerAPI) WatchContainers(args params.WatchContainers) (params.StringsWatchResults, error) {
   186  	result := params.StringsWatchResults{
   187  		Results: make([]params.StringsWatchResult, len(args.Params)),
   188  	}
   189  	for i, arg := range args.Params {
   190  		watcherResult, err := p.watchOneMachineContainers(arg)
   191  		result.Results[i] = watcherResult
   192  		result.Results[i].Error = common.ServerError(err)
   193  	}
   194  	return result, nil
   195  }
   196  
   197  // WatchAllContainers starts a StringsWatcher to watch all containers deployed to
   198  // any machine passed in args.
   199  func (p *ProvisionerAPI) WatchAllContainers(args params.WatchContainers) (params.StringsWatchResults, error) {
   200  	return p.WatchContainers(args)
   201  }
   202  
   203  // SetSupportedContainers updates the list of containers supported by the machines passed in args.
   204  func (p *ProvisionerAPI) SetSupportedContainers(args params.MachineContainersParams) (params.ErrorResults, error) {
   205  	result := params.ErrorResults{
   206  		Results: make([]params.ErrorResult, len(args.Params)),
   207  	}
   208  
   209  	canAccess, err := p.getAuthFunc()
   210  	if err != nil {
   211  		return result, err
   212  	}
   213  	for i, arg := range args.Params {
   214  		tag, err := names.ParseMachineTag(arg.MachineTag)
   215  		if err != nil {
   216  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   217  			continue
   218  		}
   219  		machine, err := p.getMachine(canAccess, tag)
   220  		if err != nil {
   221  			result.Results[i].Error = common.ServerError(err)
   222  			continue
   223  		}
   224  		if len(arg.ContainerTypes) == 0 {
   225  			err = machine.SupportsNoContainers()
   226  		} else {
   227  			err = machine.SetSupportedContainers(arg.ContainerTypes)
   228  		}
   229  		if err != nil {
   230  			result.Results[i].Error = common.ServerError(err)
   231  		}
   232  	}
   233  	return result, nil
   234  }
   235  
   236  // ContainerManagerConfig returns information from the environment config that is
   237  // needed for configuring the container manager.
   238  func (p *ProvisionerAPI) ContainerManagerConfig(args params.ContainerManagerConfigParams) (params.ContainerManagerConfig, error) {
   239  	var result params.ContainerManagerConfig
   240  	cfg := make(map[string]string)
   241  	cfg[container.ConfigModelUUID] = p.st.ModelUUID()
   242  
   243  	switch args.Type {
   244  	case instance.LXD:
   245  		// TODO(jam): DefaultMTU needs to be handled here
   246  		// TODO(jam): Do we want to handle ImageStream here, or do we
   247  		// hide it from them? (all cached images must come from the
   248  		// same image stream?)
   249  	}
   250  
   251  	result.ManagerConfig = cfg
   252  	return result, nil
   253  }
   254  
   255  // ContainerConfig returns information from the environment config that is
   256  // needed for container cloud-init.
   257  func (p *ProvisionerAPI) ContainerConfig() (params.ContainerConfig, error) {
   258  	result := params.ContainerConfig{}
   259  	config, err := p.st.ModelConfig()
   260  	if err != nil {
   261  		return result, err
   262  	}
   263  
   264  	result.UpdateBehavior = &params.UpdateBehavior{
   265  		config.EnableOSRefreshUpdate(),
   266  		config.EnableOSUpgrade(),
   267  	}
   268  	result.ProviderType = config.Type()
   269  	result.AuthorizedKeys = config.AuthorizedKeys()
   270  	result.SSLHostnameVerification = config.SSLHostnameVerification()
   271  	result.Proxy = config.ProxySettings()
   272  	result.AptProxy = config.AptProxySettings()
   273  	result.AptMirror = config.AptMirror()
   274  
   275  	return result, nil
   276  }
   277  
   278  // MachinesWithTransientErrors returns status data for machines with provisioning
   279  // errors which are transient.
   280  func (p *ProvisionerAPI) MachinesWithTransientErrors() (params.StatusResults, error) {
   281  	var results params.StatusResults
   282  	canAccessFunc, err := p.getAuthFunc()
   283  	if err != nil {
   284  		return results, err
   285  	}
   286  	// TODO (wallyworld) - add state.State API for more efficient machines query
   287  	machines, err := p.st.AllMachines()
   288  	if err != nil {
   289  		return results, err
   290  	}
   291  	for _, machine := range machines {
   292  		if !canAccessFunc(machine.Tag()) {
   293  			continue
   294  		}
   295  		if _, provisionedErr := machine.InstanceId(); provisionedErr == nil {
   296  			// Machine may have been provisioned but machiner hasn't set the
   297  			// status to Started yet.
   298  			continue
   299  		}
   300  		var result params.StatusResult
   301  		statusInfo, err := machine.Status()
   302  		if err != nil {
   303  			continue
   304  		}
   305  		result.Status = statusInfo.Status.String()
   306  		result.Info = statusInfo.Message
   307  		result.Data = statusInfo.Data
   308  		if statusInfo.Status != status.Error {
   309  			continue
   310  		}
   311  		// Transient errors are marked as such in the status data.
   312  		if transient, ok := result.Data["transient"].(bool); !ok || !transient {
   313  			continue
   314  		}
   315  		result.Id = machine.Id()
   316  		result.Life = params.Life(machine.Life().String())
   317  		results.Results = append(results.Results, result)
   318  	}
   319  	return results, nil
   320  }
   321  
   322  // Series returns the deployed series for each given machine entity.
   323  func (p *ProvisionerAPI) Series(args params.Entities) (params.StringResults, error) {
   324  	result := params.StringResults{
   325  		Results: make([]params.StringResult, len(args.Entities)),
   326  	}
   327  	canAccess, err := p.getAuthFunc()
   328  	if err != nil {
   329  		return result, err
   330  	}
   331  	for i, entity := range args.Entities {
   332  		tag, err := names.ParseMachineTag(entity.Tag)
   333  		if err != nil {
   334  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   335  			continue
   336  		}
   337  		machine, err := p.getMachine(canAccess, tag)
   338  		if err == nil {
   339  			result.Results[i].Result = machine.Series()
   340  		}
   341  		result.Results[i].Error = common.ServerError(err)
   342  	}
   343  	return result, nil
   344  }
   345  
   346  // DistributionGroup returns, for each given machine entity,
   347  // a slice of instance.Ids that belong to the same distribution
   348  // group as that machine. This information may be used to
   349  // distribute instances for high availability.
   350  func (p *ProvisionerAPI) DistributionGroup(args params.Entities) (params.DistributionGroupResults, error) {
   351  	result := params.DistributionGroupResults{
   352  		Results: make([]params.DistributionGroupResult, len(args.Entities)),
   353  	}
   354  	canAccess, err := p.getAuthFunc()
   355  	if err != nil {
   356  		return result, err
   357  	}
   358  	for i, entity := range args.Entities {
   359  		tag, err := names.ParseMachineTag(entity.Tag)
   360  		if err != nil {
   361  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   362  			continue
   363  		}
   364  		machine, err := p.getMachine(canAccess, tag)
   365  		if err == nil {
   366  			// If the machine is an environment manager, return
   367  			// environment manager instances. Otherwise, return
   368  			// instances with services in common with the machine
   369  			// being provisioned.
   370  			if machine.IsManager() {
   371  				result.Results[i].Result, err = environManagerInstances(p.st)
   372  			} else {
   373  				result.Results[i].Result, err = commonServiceInstances(p.st, machine)
   374  			}
   375  		}
   376  		result.Results[i].Error = common.ServerError(err)
   377  	}
   378  	return result, nil
   379  }
   380  
   381  // environManagerInstances returns all environ manager instances.
   382  func environManagerInstances(st *state.State) ([]instance.Id, error) {
   383  	info, err := st.ControllerInfo()
   384  	if err != nil {
   385  		return nil, err
   386  	}
   387  	instances := make([]instance.Id, 0, len(info.MachineIds))
   388  	for _, id := range info.MachineIds {
   389  		machine, err := st.Machine(id)
   390  		if err != nil {
   391  			return nil, err
   392  		}
   393  		instanceId, err := machine.InstanceId()
   394  		if err == nil {
   395  			instances = append(instances, instanceId)
   396  		} else if !errors.IsNotProvisioned(err) {
   397  			return nil, err
   398  		}
   399  	}
   400  	return instances, nil
   401  }
   402  
   403  // commonServiceInstances returns instances with
   404  // services in common with the specified machine.
   405  func commonServiceInstances(st *state.State, m *state.Machine) ([]instance.Id, error) {
   406  	units, err := m.Units()
   407  	if err != nil {
   408  		return nil, err
   409  	}
   410  	instanceIdSet := make(set.Strings)
   411  	for _, unit := range units {
   412  		if !unit.IsPrincipal() {
   413  			continue
   414  		}
   415  		instanceIds, err := state.ServiceInstances(st, unit.ApplicationName())
   416  		if err != nil {
   417  			return nil, err
   418  		}
   419  		for _, instanceId := range instanceIds {
   420  			instanceIdSet.Add(string(instanceId))
   421  		}
   422  	}
   423  	instanceIds := make([]instance.Id, instanceIdSet.Size())
   424  	// Sort values to simplify testing.
   425  	for i, instanceId := range instanceIdSet.SortedValues() {
   426  		instanceIds[i] = instance.Id(instanceId)
   427  	}
   428  	return instanceIds, nil
   429  }
   430  
   431  // Constraints returns the constraints for each given machine entity.
   432  func (p *ProvisionerAPI) Constraints(args params.Entities) (params.ConstraintsResults, error) {
   433  	result := params.ConstraintsResults{
   434  		Results: make([]params.ConstraintsResult, len(args.Entities)),
   435  	}
   436  	canAccess, err := p.getAuthFunc()
   437  	if err != nil {
   438  		return result, err
   439  	}
   440  	for i, entity := range args.Entities {
   441  		tag, err := names.ParseMachineTag(entity.Tag)
   442  		if err != nil {
   443  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   444  			continue
   445  		}
   446  		machine, err := p.getMachine(canAccess, tag)
   447  		if err == nil {
   448  			var cons constraints.Value
   449  			cons, err = machine.Constraints()
   450  			if err == nil {
   451  				result.Results[i].Constraints = cons
   452  			}
   453  		}
   454  		result.Results[i].Error = common.ServerError(err)
   455  	}
   456  	return result, nil
   457  }
   458  
   459  // SetInstanceInfo sets the provider specific machine id, nonce,
   460  // metadata and network info for each given machine. Once set, the
   461  // instance id cannot be changed.
   462  func (p *ProvisionerAPI) SetInstanceInfo(args params.InstancesInfo) (params.ErrorResults, error) {
   463  	result := params.ErrorResults{
   464  		Results: make([]params.ErrorResult, len(args.Machines)),
   465  	}
   466  	canAccess, err := p.getAuthFunc()
   467  	if err != nil {
   468  		return result, err
   469  	}
   470  	setInstanceInfo := func(arg params.InstanceInfo) error {
   471  		tag, err := names.ParseMachineTag(arg.Tag)
   472  		if err != nil {
   473  			return common.ErrPerm
   474  		}
   475  		machine, err := p.getMachine(canAccess, tag)
   476  		if err != nil {
   477  			return err
   478  		}
   479  		volumes, err := storagecommon.VolumesToState(arg.Volumes)
   480  		if err != nil {
   481  			return err
   482  		}
   483  		volumeAttachments, err := storagecommon.VolumeAttachmentInfosToState(arg.VolumeAttachments)
   484  		if err != nil {
   485  			return err
   486  		}
   487  
   488  		devicesArgs, devicesAddrs := networkingcommon.NetworkConfigsToStateArgs(arg.NetworkConfig)
   489  
   490  		err = machine.SetInstanceInfo(
   491  			arg.InstanceId, arg.Nonce, arg.Characteristics,
   492  			devicesArgs, devicesAddrs,
   493  			volumes, volumeAttachments,
   494  		)
   495  		if err != nil {
   496  			return errors.Annotatef(err, "cannot record provisioning info for %q", arg.InstanceId)
   497  		}
   498  		return nil
   499  	}
   500  	for i, arg := range args.Machines {
   501  		err := setInstanceInfo(arg)
   502  		result.Results[i].Error = common.ServerError(err)
   503  	}
   504  	return result, nil
   505  }
   506  
   507  // WatchMachineErrorRetry returns a NotifyWatcher that notifies when
   508  // the provisioner should retry provisioning machines with transient errors.
   509  func (p *ProvisionerAPI) WatchMachineErrorRetry() (params.NotifyWatchResult, error) {
   510  	result := params.NotifyWatchResult{}
   511  	if !p.authorizer.AuthModelManager() {
   512  		return result, common.ErrPerm
   513  	}
   514  	watch := newWatchMachineErrorRetry()
   515  	// Consume any initial event and forward it to the result.
   516  	if _, ok := <-watch.Changes(); ok {
   517  		result.NotifyWatcherId = p.resources.Register(watch)
   518  	} else {
   519  		return result, watcher.EnsureErr(watch)
   520  	}
   521  	return result, nil
   522  }
   523  
   524  // ReleaseContainerAddresses finds addresses allocated to a container and marks
   525  // them as Dead, to be released and removed. It accepts container tags as
   526  // arguments.
   527  func (p *ProvisionerAPI) ReleaseContainerAddresses(args params.Entities) (params.ErrorResults, error) {
   528  	result := params.ErrorResults{
   529  		Results: make([]params.ErrorResult, len(args.Entities)),
   530  	}
   531  
   532  	canAccess, err := p.getAuthFunc()
   533  	if err != nil {
   534  		logger.Errorf("failed to get an authorisation function: %v", err)
   535  		return result, errors.Trace(err)
   536  	}
   537  	// Loop over the passed container tags.
   538  	for i, entity := range args.Entities {
   539  		tag, err := names.ParseMachineTag(entity.Tag)
   540  		if err != nil {
   541  			logger.Warningf("failed to parse machine tag %q: %v", entity.Tag, err)
   542  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   543  			continue
   544  		}
   545  
   546  		// The auth function (canAccess) checks that the machine is a
   547  		// top level machine (we filter those out next) or that the
   548  		// machine has the host as a parent.
   549  		container, err := p.getMachine(canAccess, tag)
   550  		if err != nil {
   551  			logger.Warningf("failed to get machine %q: %v", tag, err)
   552  			result.Results[i].Error = common.ServerError(err)
   553  			continue
   554  		} else if !container.IsContainer() {
   555  			err = errors.Errorf("cannot mark addresses for removal for %q: not a container", tag)
   556  			result.Results[i].Error = common.ServerError(err)
   557  			continue
   558  		}
   559  
   560  		// TODO(dimitern): Release those via the provider once we have
   561  		// Environ.ReleaseContainerAddresses. See LP bug http://pad.lv/1585878
   562  		err = container.RemoveAllAddresses()
   563  		if err != nil {
   564  			logger.Warningf("failed to remove container %q addresses: %v", tag, err)
   565  			result.Results[i].Error = common.ServerError(err)
   566  			continue
   567  		}
   568  	}
   569  
   570  	return result, nil
   571  }
   572  
   573  // PrepareContainerInterfaceInfo allocates an address and returns information to
   574  // configure networking for a container. It accepts container tags as arguments.
   575  func (p *ProvisionerAPI) PrepareContainerInterfaceInfo(args params.Entities) (
   576  	params.MachineNetworkConfigResults,
   577  	error,
   578  ) {
   579  	return p.prepareOrGetContainerInterfaceInfo(args, false)
   580  }
   581  
   582  // GetContainerInterfaceInfo returns information to configure networking for a
   583  // container. It accepts container tags as arguments.
   584  func (p *ProvisionerAPI) GetContainerInterfaceInfo(args params.Entities) (
   585  	params.MachineNetworkConfigResults,
   586  	error,
   587  ) {
   588  	return p.prepareOrGetContainerInterfaceInfo(args, true)
   589  }
   590  
   591  func (p *ProvisionerAPI) prepareOrGetContainerInterfaceInfo(args params.Entities, maintain bool) (params.MachineNetworkConfigResults, error) {
   592  	result := params.MachineNetworkConfigResults{
   593  		Results: make([]params.MachineNetworkConfigResult, len(args.Entities)),
   594  	}
   595  
   596  	netEnviron, hostMachine, canAccess, err := p.prepareContainerAccessEnvironment()
   597  	if err != nil {
   598  		return result, errors.Trace(err)
   599  	}
   600  	instId, err := hostMachine.InstanceId()
   601  	if errors.IsNotProvisioned(err) {
   602  		err = errors.NotProvisionedf("cannot prepare container network config: host machine %q", hostMachine)
   603  		return result, err
   604  	} else if err != nil {
   605  		return result, errors.Trace(err)
   606  	}
   607  
   608  	for i, entity := range args.Entities {
   609  		machineTag, err := names.ParseMachineTag(entity.Tag)
   610  		if err != nil {
   611  			result.Results[i].Error = common.ServerError(err)
   612  			continue
   613  		}
   614  		// The auth function (canAccess) checks that the machine is a
   615  		// top level machine (we filter those out next) or that the
   616  		// machine has the host as a parent.
   617  		container, err := p.getMachine(canAccess, machineTag)
   618  		if err != nil {
   619  			result.Results[i].Error = common.ServerError(err)
   620  			continue
   621  		} else if !container.IsContainer() {
   622  			err = errors.Errorf("cannot prepare network config for %q: not a container", machineTag)
   623  			result.Results[i].Error = common.ServerError(err)
   624  			continue
   625  		} else if ciid, cerr := container.InstanceId(); maintain == true && cerr == nil {
   626  			// Since we want to configure and create NICs on the
   627  			// container before it starts, it must also be not
   628  			// provisioned yet.
   629  			err = errors.Errorf("container %q already provisioned as %q", container, ciid)
   630  			result.Results[i].Error = common.ServerError(err)
   631  			continue
   632  		} else if cerr != nil && !errors.IsNotProvisioned(cerr) {
   633  			// Any other error needs to be reported.
   634  			result.Results[i].Error = common.ServerError(cerr)
   635  			continue
   636  		}
   637  
   638  		if err := hostMachine.SetContainerLinkLayerDevices(container); err != nil {
   639  			result.Results[i].Error = common.ServerError(err)
   640  			continue
   641  		}
   642  
   643  		containerDevices, err := container.AllLinkLayerDevices()
   644  		if err != nil {
   645  			result.Results[i].Error = common.ServerError(err)
   646  			continue
   647  		}
   648  
   649  		preparedInfo := make([]network.InterfaceInfo, len(containerDevices))
   650  		preparedOK := true
   651  		for j, device := range containerDevices {
   652  			parentDevice, err := device.ParentDevice()
   653  			if err != nil || parentDevice == nil {
   654  				err = errors.Errorf(
   655  					"cannot get parent %q of container device %q: %v",
   656  					device.ParentName(), device.Name(), err,
   657  				)
   658  				result.Results[i].Error = common.ServerError(err)
   659  				preparedOK = false
   660  				break
   661  			}
   662  			parentAddrs, err := parentDevice.Addresses()
   663  			if err != nil {
   664  				result.Results[i].Error = common.ServerError(err)
   665  				preparedOK = false
   666  				break
   667  			}
   668  
   669  			info := network.InterfaceInfo{
   670  				InterfaceName:       device.Name(),
   671  				MACAddress:          device.MACAddress(),
   672  				ConfigType:          network.ConfigManual,
   673  				InterfaceType:       network.InterfaceType(device.Type()),
   674  				NoAutoStart:         !device.IsAutoStart(),
   675  				Disabled:            !device.IsUp(),
   676  				MTU:                 int(device.MTU()),
   677  				ParentInterfaceName: parentDevice.Name(),
   678  			}
   679  
   680  			if len(parentAddrs) > 0 {
   681  				logger.Infof("host machine device %q has addresses %v", parentDevice.Name(), parentAddrs)
   682  
   683  				firstAddress := parentAddrs[0]
   684  				parentDeviceSubnet, err := firstAddress.Subnet()
   685  				if err != nil {
   686  					err = errors.Annotatef(err,
   687  						"cannot get subnet %q used by address %q of host machine device %q",
   688  						firstAddress.SubnetCIDR(), firstAddress.Value(), parentDevice.Name(),
   689  					)
   690  					result.Results[i].Error = common.ServerError(err)
   691  					preparedOK = false
   692  					break
   693  				}
   694  				info.ConfigType = network.ConfigStatic
   695  				info.CIDR = parentDeviceSubnet.CIDR()
   696  				info.ProviderSubnetId = parentDeviceSubnet.ProviderId()
   697  				info.VLANTag = parentDeviceSubnet.VLANTag()
   698  			} else {
   699  				logger.Infof("host machine device %q has no addresses %v", parentDevice.Name(), parentAddrs)
   700  			}
   701  
   702  			logger.Tracef("prepared info for container interface %q: %+v", info.InterfaceName, info)
   703  			preparedOK = true
   704  			preparedInfo[j] = info
   705  		}
   706  
   707  		if !preparedOK {
   708  			// Error result is already set.
   709  			continue
   710  		}
   711  
   712  		allocatedInfo, err := netEnviron.AllocateContainerAddresses(instId, machineTag, preparedInfo)
   713  		if err != nil {
   714  			result.Results[i].Error = common.ServerError(err)
   715  			continue
   716  		}
   717  		logger.Debugf("got allocated info from provider: %+v", allocatedInfo)
   718  
   719  		allocatedConfig := networkingcommon.NetworkConfigFromInterfaceInfo(allocatedInfo)
   720  		logger.Tracef("allocated network config: %+v", allocatedConfig)
   721  		result.Results[i].Config = allocatedConfig
   722  	}
   723  	return result, nil
   724  }
   725  
   726  // prepareContainerAccessEnvironment retrieves the environment, host machine, and access
   727  // for working with containers.
   728  func (p *ProvisionerAPI) prepareContainerAccessEnvironment() (environs.NetworkingEnviron, *state.Machine, common.AuthFunc, error) {
   729  	netEnviron, err := networkingcommon.NetworkingEnvironFromModelConfig(p.configGetter)
   730  	if err != nil {
   731  		return nil, nil, nil, errors.Trace(err)
   732  	}
   733  
   734  	canAccess, err := p.getAuthFunc()
   735  	if err != nil {
   736  		return nil, nil, nil, errors.Annotate(err, "cannot authenticate request")
   737  	}
   738  	hostAuthTag := p.authorizer.GetAuthTag()
   739  	if hostAuthTag == nil {
   740  		return nil, nil, nil, errors.Errorf("authenticated entity tag is nil")
   741  	}
   742  	hostTag, err := names.ParseMachineTag(hostAuthTag.String())
   743  	if err != nil {
   744  		return nil, nil, nil, errors.Trace(err)
   745  	}
   746  	host, err := p.getMachine(canAccess, hostTag)
   747  	if err != nil {
   748  		return nil, nil, nil, errors.Trace(err)
   749  	}
   750  	return netEnviron, host, canAccess, nil
   751  }
   752  
   753  // InstanceStatus returns the instance status for each given entity.
   754  // Only machine tags are accepted.
   755  func (p *ProvisionerAPI) InstanceStatus(args params.Entities) (params.StatusResults, error) {
   756  	result := params.StatusResults{
   757  		Results: make([]params.StatusResult, len(args.Entities)),
   758  	}
   759  	canAccess, err := p.getAuthFunc()
   760  	if err != nil {
   761  		logger.Errorf("failed to get an authorisation function: %v", err)
   762  		return result, errors.Trace(err)
   763  	}
   764  	for i, arg := range args.Entities {
   765  		mTag, err := names.ParseMachineTag(arg.Tag)
   766  		if err != nil {
   767  			result.Results[i].Error = common.ServerError(err)
   768  			continue
   769  		}
   770  		machine, err := p.getMachine(canAccess, mTag)
   771  		if err == nil {
   772  			var statusInfo status.StatusInfo
   773  			statusInfo, err = machine.InstanceStatus()
   774  			result.Results[i].Status = statusInfo.Status.String()
   775  			result.Results[i].Info = statusInfo.Message
   776  			result.Results[i].Data = statusInfo.Data
   777  			result.Results[i].Since = statusInfo.Since
   778  		}
   779  		result.Results[i].Error = common.ServerError(err)
   780  	}
   781  	return result, nil
   782  }
   783  
   784  // SetInstanceStatus updates the instance status for each given
   785  // entity. Only machine tags are accepted.
   786  func (p *ProvisionerAPI) SetInstanceStatus(args params.SetStatus) (params.ErrorResults, error) {
   787  	result := params.ErrorResults{
   788  		Results: make([]params.ErrorResult, len(args.Entities)),
   789  	}
   790  	canAccess, err := p.getAuthFunc()
   791  	if err != nil {
   792  		logger.Errorf("failed to get an authorisation function: %v", err)
   793  		return result, errors.Trace(err)
   794  	}
   795  	for i, arg := range args.Entities {
   796  		mTag, err := names.ParseMachineTag(arg.Tag)
   797  		if err != nil {
   798  			result.Results[i].Error = common.ServerError(err)
   799  			continue
   800  		}
   801  		machine, err := p.getMachine(canAccess, mTag)
   802  		if err == nil {
   803  			// TODO(perrito666) 2016-05-02 lp:1558657
   804  			now := time.Now()
   805  			s := status.StatusInfo{
   806  				Status:  status.Status(arg.Status),
   807  				Message: arg.Info,
   808  				Data:    arg.Data,
   809  				Since:   &now,
   810  			}
   811  			err = machine.SetInstanceStatus(s)
   812  			if status.Status(arg.Status) == status.ProvisioningError {
   813  				s.Status = status.Error
   814  				if err == nil {
   815  					err = machine.SetStatus(s)
   816  				}
   817  			}
   818  		}
   819  		result.Results[i].Error = common.ServerError(err)
   820  	}
   821  	return result, nil
   822  }
   823  
   824  // MarkMachinesForRemoval indicates that the specified machines are
   825  // ready to have any provider-level resources cleaned up and then be
   826  // removed.
   827  func (p *ProvisionerAPI) MarkMachinesForRemoval(machines params.Entities) (params.ErrorResults, error) {
   828  	results := make([]params.ErrorResult, len(machines.Entities))
   829  	canAccess, err := p.getAuthFunc()
   830  	if err != nil {
   831  		logger.Errorf("failed to get an authorisation function: %v", err)
   832  		return params.ErrorResults{}, errors.Trace(err)
   833  	}
   834  	for i, machine := range machines.Entities {
   835  		results[i].Error = common.ServerError(p.markOneMachineForRemoval(machine.Tag, canAccess))
   836  	}
   837  	return params.ErrorResults{Results: results}, nil
   838  }
   839  
   840  func (p *ProvisionerAPI) markOneMachineForRemoval(machineTag string, canAccess common.AuthFunc) error {
   841  	mTag, err := names.ParseMachineTag(machineTag)
   842  	if err != nil {
   843  		return errors.Trace(err)
   844  	}
   845  	machine, err := p.getMachine(canAccess, mTag)
   846  	if err != nil {
   847  		return errors.Trace(err)
   848  	}
   849  	return machine.MarkForRemoval()
   850  }