github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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  	"fmt"
     8  	"math/rand"
     9  
    10  	"github.com/juju/errors"
    11  	"github.com/juju/loggo"
    12  	"github.com/juju/names"
    13  	"github.com/juju/utils/set"
    14  
    15  	"github.com/juju/juju/apiserver/common"
    16  	"github.com/juju/juju/apiserver/common/networkingcommon"
    17  	"github.com/juju/juju/apiserver/common/storagecommon"
    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/provider"
    25  	"github.com/juju/juju/state"
    26  	"github.com/juju/juju/state/watcher"
    27  	"github.com/juju/juju/status"
    28  )
    29  
    30  var logger = loggo.GetLogger("juju.apiserver.provisioner")
    31  
    32  func init() {
    33  	common.RegisterStandardFacade("Provisioner", 1, NewProvisionerAPI)
    34  
    35  	// Version 1 has the same set of methods as 0, with the same
    36  	// signatures, but its ProvisioningInfo returns additional
    37  	// information. Clients may require version 1 so that they
    38  	// receive this additional information; otherwise they are
    39  	// compatible.
    40  	common.RegisterStandardFacade("Provisioner", 2, NewProvisionerAPI)
    41  }
    42  
    43  // ProvisionerAPI provides access to the Provisioner API facade.
    44  type ProvisionerAPI struct {
    45  	*common.Remover
    46  	*common.StatusSetter
    47  	*common.StatusGetter
    48  	*common.DeadEnsurer
    49  	*common.PasswordChanger
    50  	*common.LifeGetter
    51  	*common.StateAddresser
    52  	*common.APIAddresser
    53  	*common.ModelWatcher
    54  	*common.ModelMachinesWatcher
    55  	*common.InstanceIdGetter
    56  	*common.ToolsFinder
    57  	*common.ToolsGetter
    58  
    59  	st          *state.State
    60  	resources   *common.Resources
    61  	authorizer  common.Authorizer
    62  	getAuthFunc common.GetAuthFunc
    63  }
    64  
    65  // NewProvisionerAPI creates a new server-side ProvisionerAPI facade.
    66  func NewProvisionerAPI(st *state.State, resources *common.Resources, authorizer common.Authorizer) (*ProvisionerAPI, error) {
    67  	if !authorizer.AuthMachineAgent() && !authorizer.AuthModelManager() {
    68  		return nil, common.ErrPerm
    69  	}
    70  	getAuthFunc := func() (common.AuthFunc, error) {
    71  		isModelManager := authorizer.AuthModelManager()
    72  		isMachineAgent := authorizer.AuthMachineAgent()
    73  		authEntityTag := authorizer.GetAuthTag()
    74  
    75  		return func(tag names.Tag) bool {
    76  			if isMachineAgent && tag == authEntityTag {
    77  				// A machine agent can always access its own machine.
    78  				return true
    79  			}
    80  			switch tag := tag.(type) {
    81  			case names.MachineTag:
    82  				parentId := state.ParentId(tag.Id())
    83  				if parentId == "" {
    84  					// All top-level machines are accessible by the
    85  					// environment manager.
    86  					return isModelManager
    87  				}
    88  				// All containers with the authenticated machine as a
    89  				// parent are accessible by it.
    90  				// TODO(dfc) sometimes authEntity tag is nil, which is fine because nil is
    91  				// only equal to nil, but it suggests someone is passing an authorizer
    92  				// with a nil tag.
    93  				return isMachineAgent && names.NewMachineTag(parentId) == authEntityTag
    94  			default:
    95  				return false
    96  			}
    97  		}, nil
    98  	}
    99  	getAuthOwner := func() (common.AuthFunc, error) {
   100  		return authorizer.AuthOwner, nil
   101  	}
   102  	env, err := st.Model()
   103  	if err != nil {
   104  		return nil, err
   105  	}
   106  	urlGetter := common.NewToolsURLGetter(env.UUID(), st)
   107  	return &ProvisionerAPI{
   108  		Remover:              common.NewRemover(st, false, getAuthFunc),
   109  		StatusSetter:         common.NewStatusSetter(st, getAuthFunc),
   110  		StatusGetter:         common.NewStatusGetter(st, getAuthFunc),
   111  		DeadEnsurer:          common.NewDeadEnsurer(st, getAuthFunc),
   112  		PasswordChanger:      common.NewPasswordChanger(st, getAuthFunc),
   113  		LifeGetter:           common.NewLifeGetter(st, getAuthFunc),
   114  		StateAddresser:       common.NewStateAddresser(st),
   115  		APIAddresser:         common.NewAPIAddresser(st, resources),
   116  		ModelWatcher:         common.NewModelWatcher(st, resources, authorizer),
   117  		ModelMachinesWatcher: common.NewModelMachinesWatcher(st, resources, authorizer),
   118  		InstanceIdGetter:     common.NewInstanceIdGetter(st, getAuthFunc),
   119  		ToolsFinder:          common.NewToolsFinder(st, st, urlGetter),
   120  		ToolsGetter:          common.NewToolsGetter(st, st, st, urlGetter, getAuthOwner),
   121  		st:                   st,
   122  		resources:            resources,
   123  		authorizer:           authorizer,
   124  		getAuthFunc:          getAuthFunc,
   125  	}, nil
   126  }
   127  
   128  func (p *ProvisionerAPI) getMachine(canAccess common.AuthFunc, tag names.MachineTag) (*state.Machine, error) {
   129  	if !canAccess(tag) {
   130  		return nil, common.ErrPerm
   131  	}
   132  	entity, err := p.st.FindEntity(tag)
   133  	if err != nil {
   134  		return nil, err
   135  	}
   136  	// The authorization function guarantees that the tag represents a
   137  	// machine.
   138  	return entity.(*state.Machine), nil
   139  }
   140  
   141  func (p *ProvisionerAPI) watchOneMachineContainers(arg params.WatchContainer) (params.StringsWatchResult, error) {
   142  	nothing := params.StringsWatchResult{}
   143  	canAccess, err := p.getAuthFunc()
   144  	if err != nil {
   145  		return nothing, common.ErrPerm
   146  	}
   147  	tag, err := names.ParseMachineTag(arg.MachineTag)
   148  	if err != nil {
   149  		return nothing, common.ErrPerm
   150  	}
   151  	if !canAccess(tag) {
   152  		return nothing, common.ErrPerm
   153  	}
   154  	machine, err := p.st.Machine(tag.Id())
   155  	if err != nil {
   156  		return nothing, err
   157  	}
   158  	var watch state.StringsWatcher
   159  	if arg.ContainerType != "" {
   160  		watch = machine.WatchContainers(instance.ContainerType(arg.ContainerType))
   161  	} else {
   162  		watch = machine.WatchAllContainers()
   163  	}
   164  	// Consume the initial event and forward it to the result.
   165  	if changes, ok := <-watch.Changes(); ok {
   166  		return params.StringsWatchResult{
   167  			StringsWatcherId: p.resources.Register(watch),
   168  			Changes:          changes,
   169  		}, nil
   170  	}
   171  	return nothing, watcher.EnsureErr(watch)
   172  }
   173  
   174  // WatchContainers starts a StringsWatcher to watch containers deployed to
   175  // any machine passed in args.
   176  func (p *ProvisionerAPI) WatchContainers(args params.WatchContainers) (params.StringsWatchResults, error) {
   177  	result := params.StringsWatchResults{
   178  		Results: make([]params.StringsWatchResult, len(args.Params)),
   179  	}
   180  	for i, arg := range args.Params {
   181  		watcherResult, err := p.watchOneMachineContainers(arg)
   182  		result.Results[i] = watcherResult
   183  		result.Results[i].Error = common.ServerError(err)
   184  	}
   185  	return result, nil
   186  }
   187  
   188  // WatchAllContainers starts a StringsWatcher to watch all containers deployed to
   189  // any machine passed in args.
   190  func (p *ProvisionerAPI) WatchAllContainers(args params.WatchContainers) (params.StringsWatchResults, error) {
   191  	return p.WatchContainers(args)
   192  }
   193  
   194  // SetSupportedContainers updates the list of containers supported by the machines passed in args.
   195  func (p *ProvisionerAPI) SetSupportedContainers(args params.MachineContainersParams) (params.ErrorResults, error) {
   196  	result := params.ErrorResults{
   197  		Results: make([]params.ErrorResult, len(args.Params)),
   198  	}
   199  
   200  	canAccess, err := p.getAuthFunc()
   201  	if err != nil {
   202  		return result, err
   203  	}
   204  	for i, arg := range args.Params {
   205  		tag, err := names.ParseMachineTag(arg.MachineTag)
   206  		if err != nil {
   207  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   208  			continue
   209  		}
   210  		machine, err := p.getMachine(canAccess, tag)
   211  		if err != nil {
   212  			result.Results[i].Error = common.ServerError(err)
   213  			continue
   214  		}
   215  		if len(arg.ContainerTypes) == 0 {
   216  			err = machine.SupportsNoContainers()
   217  		} else {
   218  			err = machine.SetSupportedContainers(arg.ContainerTypes)
   219  		}
   220  		if err != nil {
   221  			result.Results[i].Error = common.ServerError(err)
   222  		}
   223  	}
   224  	return result, nil
   225  }
   226  
   227  // ContainerManagerConfig returns information from the environment config that is
   228  // needed for configuring the container manager.
   229  func (p *ProvisionerAPI) ContainerManagerConfig(args params.ContainerManagerConfigParams) (params.ContainerManagerConfig, error) {
   230  	var result params.ContainerManagerConfig
   231  	config, err := p.st.ModelConfig()
   232  	if err != nil {
   233  		return result, err
   234  	}
   235  	cfg := make(map[string]string)
   236  	cfg[container.ConfigName] = container.DefaultNamespace
   237  
   238  	switch args.Type {
   239  	case instance.LXC:
   240  		if useLxcClone, ok := config.LXCUseClone(); ok {
   241  			cfg["use-clone"] = fmt.Sprint(useLxcClone)
   242  		}
   243  		if useLxcCloneAufs, ok := config.LXCUseCloneAUFS(); ok {
   244  			cfg["use-aufs"] = fmt.Sprint(useLxcCloneAufs)
   245  		}
   246  		if lxcDefaultMTU, ok := config.LXCDefaultMTU(); ok {
   247  			logger.Debugf("using default MTU %v for all LXC containers NICs", lxcDefaultMTU)
   248  			cfg[container.ConfigLXCDefaultMTU] = fmt.Sprintf("%d", lxcDefaultMTU)
   249  		}
   250  	case instance.LXD:
   251  		// TODO(jam): DefaultMTU needs to be handled here
   252  		// TODO(jam): Do we want to handle ImageStream here, or do we
   253  		// hide it from them? (all cached images must come from the
   254  		// same image stream?)
   255  	}
   256  
   257  	if !environs.AddressAllocationEnabled(config.Type()) {
   258  		// No need to even try checking the environ for support.
   259  		logger.Debugf("address allocation feature flag not enabled")
   260  		result.ManagerConfig = cfg
   261  		return result, nil
   262  	}
   263  
   264  	// Create an environment to verify networking support.
   265  	env, err := environs.New(config)
   266  	if err != nil {
   267  		return result, err
   268  	}
   269  	if netEnv, ok := environs.SupportsNetworking(env); ok {
   270  		// Passing network.AnySubnet below should be interpreted by
   271  		// the provider as "does ANY subnet support this".
   272  		supported, err := netEnv.SupportsAddressAllocation(network.AnySubnet)
   273  		if err == nil && supported {
   274  			cfg[container.ConfigIPForwarding] = "true"
   275  		} else if err != nil {
   276  			// We log the error, but it's safe to ignore as it's not
   277  			// critical.
   278  			logger.Debugf("address allocation not supported (%v)", err)
   279  		}
   280  		// AWS requires NAT in place in order for hosted containers to
   281  		// reach outside.
   282  		if config.Type() == provider.EC2 {
   283  			cfg[container.ConfigEnableNAT] = "true"
   284  		}
   285  	}
   286  
   287  	result.ManagerConfig = cfg
   288  	return result, nil
   289  }
   290  
   291  // ContainerConfig returns information from the environment config that is
   292  // needed for container cloud-init.
   293  func (p *ProvisionerAPI) ContainerConfig() (params.ContainerConfig, error) {
   294  	result := params.ContainerConfig{}
   295  	config, err := p.st.ModelConfig()
   296  	if err != nil {
   297  		return result, err
   298  	}
   299  
   300  	result.UpdateBehavior = &params.UpdateBehavior{
   301  		config.EnableOSRefreshUpdate(),
   302  		config.EnableOSUpgrade(),
   303  	}
   304  	result.ProviderType = config.Type()
   305  	result.AuthorizedKeys = config.AuthorizedKeys()
   306  	result.SSLHostnameVerification = config.SSLHostnameVerification()
   307  	result.Proxy = config.ProxySettings()
   308  	result.AptProxy = config.AptProxySettings()
   309  	result.AptMirror = config.AptMirror()
   310  	result.PreferIPv6 = config.PreferIPv6()
   311  	result.AllowLXCLoopMounts, _ = config.AllowLXCLoopMounts()
   312  
   313  	return result, nil
   314  }
   315  
   316  // MachinesWithTransientErrors returns status data for machines with provisioning
   317  // errors which are transient.
   318  func (p *ProvisionerAPI) MachinesWithTransientErrors() (params.StatusResults, error) {
   319  	var results params.StatusResults
   320  	canAccessFunc, err := p.getAuthFunc()
   321  	if err != nil {
   322  		return results, err
   323  	}
   324  	// TODO (wallyworld) - add state.State API for more efficient machines query
   325  	machines, err := p.st.AllMachines()
   326  	if err != nil {
   327  		return results, err
   328  	}
   329  	for _, machine := range machines {
   330  		if !canAccessFunc(machine.Tag()) {
   331  			continue
   332  		}
   333  		if _, provisionedErr := machine.InstanceId(); provisionedErr == nil {
   334  			// Machine may have been provisioned but machiner hasn't set the
   335  			// status to Started yet.
   336  			continue
   337  		}
   338  		var result params.StatusResult
   339  		statusInfo, err := machine.Status()
   340  		if err != nil {
   341  			continue
   342  		}
   343  		result.Status = status.Status(statusInfo.Status)
   344  		result.Info = statusInfo.Message
   345  		result.Data = statusInfo.Data
   346  		if result.Status != status.StatusError {
   347  			continue
   348  		}
   349  		// Transient errors are marked as such in the status data.
   350  		if transient, ok := result.Data["transient"].(bool); !ok || !transient {
   351  			continue
   352  		}
   353  		result.Id = machine.Id()
   354  		result.Life = params.Life(machine.Life().String())
   355  		results.Results = append(results.Results, result)
   356  	}
   357  	return results, nil
   358  }
   359  
   360  // Series returns the deployed series for each given machine entity.
   361  func (p *ProvisionerAPI) Series(args params.Entities) (params.StringResults, error) {
   362  	result := params.StringResults{
   363  		Results: make([]params.StringResult, len(args.Entities)),
   364  	}
   365  	canAccess, err := p.getAuthFunc()
   366  	if err != nil {
   367  		return result, err
   368  	}
   369  	for i, entity := range args.Entities {
   370  		tag, err := names.ParseMachineTag(entity.Tag)
   371  		if err != nil {
   372  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   373  			continue
   374  		}
   375  		machine, err := p.getMachine(canAccess, tag)
   376  		if err == nil {
   377  			result.Results[i].Result = machine.Series()
   378  		}
   379  		result.Results[i].Error = common.ServerError(err)
   380  	}
   381  	return result, nil
   382  }
   383  
   384  // DistributionGroup returns, for each given machine entity,
   385  // a slice of instance.Ids that belong to the same distribution
   386  // group as that machine. This information may be used to
   387  // distribute instances for high availability.
   388  func (p *ProvisionerAPI) DistributionGroup(args params.Entities) (params.DistributionGroupResults, error) {
   389  	result := params.DistributionGroupResults{
   390  		Results: make([]params.DistributionGroupResult, len(args.Entities)),
   391  	}
   392  	canAccess, err := p.getAuthFunc()
   393  	if err != nil {
   394  		return result, err
   395  	}
   396  	for i, entity := range args.Entities {
   397  		tag, err := names.ParseMachineTag(entity.Tag)
   398  		if err != nil {
   399  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   400  			continue
   401  		}
   402  		machine, err := p.getMachine(canAccess, tag)
   403  		if err == nil {
   404  			// If the machine is an environment manager, return
   405  			// environment manager instances. Otherwise, return
   406  			// instances with services in common with the machine
   407  			// being provisioned.
   408  			if machine.IsManager() {
   409  				result.Results[i].Result, err = environManagerInstances(p.st)
   410  			} else {
   411  				result.Results[i].Result, err = commonServiceInstances(p.st, machine)
   412  			}
   413  		}
   414  		result.Results[i].Error = common.ServerError(err)
   415  	}
   416  	return result, nil
   417  }
   418  
   419  // environManagerInstances returns all environ manager instances.
   420  func environManagerInstances(st *state.State) ([]instance.Id, error) {
   421  	info, err := st.ControllerInfo()
   422  	if err != nil {
   423  		return nil, err
   424  	}
   425  	instances := make([]instance.Id, 0, len(info.MachineIds))
   426  	for _, id := range info.MachineIds {
   427  		machine, err := st.Machine(id)
   428  		if err != nil {
   429  			return nil, err
   430  		}
   431  		instanceId, err := machine.InstanceId()
   432  		if err == nil {
   433  			instances = append(instances, instanceId)
   434  		} else if !errors.IsNotProvisioned(err) {
   435  			return nil, err
   436  		}
   437  	}
   438  	return instances, nil
   439  }
   440  
   441  // commonServiceInstances returns instances with
   442  // services in common with the specified machine.
   443  func commonServiceInstances(st *state.State, m *state.Machine) ([]instance.Id, error) {
   444  	units, err := m.Units()
   445  	if err != nil {
   446  		return nil, err
   447  	}
   448  	instanceIdSet := make(set.Strings)
   449  	for _, unit := range units {
   450  		if !unit.IsPrincipal() {
   451  			continue
   452  		}
   453  		instanceIds, err := state.ServiceInstances(st, unit.ServiceName())
   454  		if err != nil {
   455  			return nil, err
   456  		}
   457  		for _, instanceId := range instanceIds {
   458  			instanceIdSet.Add(string(instanceId))
   459  		}
   460  	}
   461  	instanceIds := make([]instance.Id, instanceIdSet.Size())
   462  	// Sort values to simplify testing.
   463  	for i, instanceId := range instanceIdSet.SortedValues() {
   464  		instanceIds[i] = instance.Id(instanceId)
   465  	}
   466  	return instanceIds, nil
   467  }
   468  
   469  // Constraints returns the constraints for each given machine entity.
   470  func (p *ProvisionerAPI) Constraints(args params.Entities) (params.ConstraintsResults, error) {
   471  	result := params.ConstraintsResults{
   472  		Results: make([]params.ConstraintsResult, len(args.Entities)),
   473  	}
   474  	canAccess, err := p.getAuthFunc()
   475  	if err != nil {
   476  		return result, err
   477  	}
   478  	for i, entity := range args.Entities {
   479  		tag, err := names.ParseMachineTag(entity.Tag)
   480  		if err != nil {
   481  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   482  			continue
   483  		}
   484  		machine, err := p.getMachine(canAccess, tag)
   485  		if err == nil {
   486  			var cons constraints.Value
   487  			cons, err = machine.Constraints()
   488  			if err == nil {
   489  				result.Results[i].Constraints = cons
   490  			}
   491  		}
   492  		result.Results[i].Error = common.ServerError(err)
   493  	}
   494  	return result, nil
   495  }
   496  
   497  // SetInstanceInfo sets the provider specific machine id, nonce,
   498  // metadata and network info for each given machine. Once set, the
   499  // instance id cannot be changed.
   500  func (p *ProvisionerAPI) SetInstanceInfo(args params.InstancesInfo) (params.ErrorResults, error) {
   501  	result := params.ErrorResults{
   502  		Results: make([]params.ErrorResult, len(args.Machines)),
   503  	}
   504  	canAccess, err := p.getAuthFunc()
   505  	if err != nil {
   506  		return result, err
   507  	}
   508  	setInstanceInfo := func(arg params.InstanceInfo) error {
   509  		tag, err := names.ParseMachineTag(arg.Tag)
   510  		if err != nil {
   511  			return common.ErrPerm
   512  		}
   513  		machine, err := p.getMachine(canAccess, tag)
   514  		if err != nil {
   515  			return err
   516  		}
   517  		volumes, err := storagecommon.VolumesToState(arg.Volumes)
   518  		if err != nil {
   519  			return err
   520  		}
   521  		volumeAttachments, err := storagecommon.VolumeAttachmentInfosToState(arg.VolumeAttachments)
   522  		if err != nil {
   523  			return err
   524  		}
   525  
   526  		devicesArgs, devicesAddrs := networkingcommon.NetworkConfigsToStateArgs(arg.NetworkConfig)
   527  
   528  		err = machine.SetInstanceInfo(
   529  			arg.InstanceId, arg.Nonce, arg.Characteristics,
   530  			devicesArgs, devicesAddrs,
   531  			volumes, volumeAttachments,
   532  		)
   533  		if err != nil {
   534  			return errors.Annotatef(err, "cannot record provisioning info for %q", arg.InstanceId)
   535  		}
   536  		return nil
   537  	}
   538  	for i, arg := range args.Machines {
   539  		err := setInstanceInfo(arg)
   540  		result.Results[i].Error = common.ServerError(err)
   541  	}
   542  	return result, nil
   543  }
   544  
   545  // WatchMachineErrorRetry returns a NotifyWatcher that notifies when
   546  // the provisioner should retry provisioning machines with transient errors.
   547  func (p *ProvisionerAPI) WatchMachineErrorRetry() (params.NotifyWatchResult, error) {
   548  	result := params.NotifyWatchResult{}
   549  	if !p.authorizer.AuthModelManager() {
   550  		return result, common.ErrPerm
   551  	}
   552  	watch := newWatchMachineErrorRetry()
   553  	// Consume any initial event and forward it to the result.
   554  	if _, ok := <-watch.Changes(); ok {
   555  		result.NotifyWatcherId = p.resources.Register(watch)
   556  	} else {
   557  		return result, watcher.EnsureErr(watch)
   558  	}
   559  	return result, nil
   560  }
   561  
   562  func containerHostname(containerTag names.Tag) string {
   563  	return fmt.Sprintf("%s-%s", container.DefaultNamespace, containerTag.String())
   564  }
   565  
   566  // ReleaseContainerAddresses finds addresses allocated to a container
   567  // and marks them as Dead, to be released and removed. It accepts
   568  // container tags as arguments. If address allocation feature flag is
   569  // not enabled, it will return a NotSupported error.
   570  func (p *ProvisionerAPI) ReleaseContainerAddresses(args params.Entities) (params.ErrorResults, error) {
   571  	result := params.ErrorResults{
   572  		Results: make([]params.ErrorResult, len(args.Entities)),
   573  	}
   574  
   575  	canAccess, err := p.getAuthFunc()
   576  	if err != nil {
   577  		logger.Errorf("failed to get an authorisation function: %v", err)
   578  		return result, errors.Trace(err)
   579  	}
   580  	// Loop over the passed container tags.
   581  	for i, entity := range args.Entities {
   582  		tag, err := names.ParseMachineTag(entity.Tag)
   583  		if err != nil {
   584  			logger.Warningf("failed to parse machine tag %q: %v", entity.Tag, err)
   585  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   586  			continue
   587  		}
   588  
   589  		// The auth function (canAccess) checks that the machine is a
   590  		// top level machine (we filter those out next) or that the
   591  		// machine has the host as a parent.
   592  		container, err := p.getMachine(canAccess, tag)
   593  		if err != nil {
   594  			logger.Warningf("failed to get machine %q: %v", tag, err)
   595  			result.Results[i].Error = common.ServerError(err)
   596  			continue
   597  		} else if !container.IsContainer() {
   598  			err = errors.Errorf("cannot mark addresses for removal for %q: not a container", tag)
   599  			result.Results[i].Error = common.ServerError(err)
   600  			continue
   601  		}
   602  
   603  		id := container.Id()
   604  		addresses, err := p.st.AllocatedIPAddresses(id)
   605  		if err != nil {
   606  			logger.Warningf("failed to get Id for container %q: %v", tag, err)
   607  			result.Results[i].Error = common.ServerError(err)
   608  			continue
   609  		}
   610  
   611  		deadErrors := []error{}
   612  		logger.Debugf("for container %q found addresses %v", tag, addresses)
   613  		for _, addr := range addresses {
   614  			err = addr.EnsureDead()
   615  			if err != nil {
   616  				deadErrors = append(deadErrors, err)
   617  				continue
   618  			}
   619  		}
   620  		if len(deadErrors) != 0 {
   621  			err = errors.Errorf("failed to mark all addresses for removal for %q: %v", tag, deadErrors)
   622  			result.Results[i].Error = common.ServerError(err)
   623  		}
   624  	}
   625  
   626  	return result, nil
   627  }
   628  
   629  func (p *ProvisionerAPI) legacyAddressAllocationSupported() (bool, error) {
   630  	config, err := p.st.ModelConfig()
   631  	if err != nil {
   632  		return false, errors.Trace(err)
   633  	}
   634  	return environs.AddressAllocationEnabled(config.Type()), nil
   635  }
   636  
   637  // PrepareContainerInterfaceInfo allocates an address and returns
   638  // information to configure networking for a container. It accepts
   639  // container tags as arguments. If the address allocation feature flag
   640  // is not enabled, it returns a NotSupported error.
   641  func (p *ProvisionerAPI) PrepareContainerInterfaceInfo(args params.Entities) (
   642  	params.MachineNetworkConfigResults,
   643  	error,
   644  ) {
   645  	supported, err := p.legacyAddressAllocationSupported()
   646  	if err != nil {
   647  		return params.MachineNetworkConfigResults{}, errors.Trace(err)
   648  	}
   649  	if supported {
   650  		logger.Warningf("address allocation enabled - using legacyPrepareOrGetContainerInterfaceInfo(true)")
   651  		return p.legacyPrepareOrGetContainerInterfaceInfo(args, true)
   652  	}
   653  	return p.prepareOrGetContainerInterfaceInfo(args, true)
   654  }
   655  
   656  // GetContainerInterfaceInfo returns information to configure networking
   657  // for a container. It accepts container tags as arguments. If the address
   658  // allocation feature flag is not enabled, it returns a NotSupported error.
   659  func (p *ProvisionerAPI) GetContainerInterfaceInfo(args params.Entities) (
   660  	params.MachineNetworkConfigResults,
   661  	error,
   662  ) {
   663  	supported, err := p.legacyAddressAllocationSupported()
   664  	if err != nil {
   665  		return params.MachineNetworkConfigResults{}, errors.Trace(err)
   666  	}
   667  	if supported {
   668  		logger.Warningf("address allocation enabled - using legacyPrepareOrGetContainerInterfaceInfo(false)")
   669  		return p.legacyPrepareOrGetContainerInterfaceInfo(args, false)
   670  	}
   671  	return p.prepareOrGetContainerInterfaceInfo(args, false)
   672  }
   673  
   674  // MACAddressTemplate is used to generate a unique MAC address for a
   675  // container. Every '%x' is replaced by a random hexadecimal digit,
   676  // while the rest is kept as-is.
   677  const MACAddressTemplate = "00:16:3e:%02x:%02x:%02x"
   678  
   679  // generateMACAddress creates a random MAC address within the space defined by
   680  // MACAddressTemplate above.
   681  //
   682  // TODO(dimitern): We should make a best effort to ensure the MAC address we
   683  // generate is unique at least within the current environment.
   684  func generateMACAddress() string {
   685  	digits := make([]interface{}, 3)
   686  	for i := range digits {
   687  		digits[i] = rand.Intn(256)
   688  	}
   689  	return fmt.Sprintf(MACAddressTemplate, digits...)
   690  }
   691  
   692  func (p *ProvisionerAPI) prepareOrGetContainerInterfaceInfo(args params.Entities, maintain bool) (params.MachineNetworkConfigResults, error) {
   693  	result := params.MachineNetworkConfigResults{
   694  		Results: make([]params.MachineNetworkConfigResult, len(args.Entities)),
   695  	}
   696  
   697  	netEnviron, hostMachine, canAccess, err := p.prepareContainerAccessEnvironment()
   698  	if err != nil {
   699  		return result, errors.Trace(err)
   700  	}
   701  	instId, err := hostMachine.InstanceId()
   702  	if errors.IsNotProvisioned(err) {
   703  		err = errors.NotProvisionedf("cannot prepare container network config: host machine %q", hostMachine)
   704  		return result, err
   705  	} else if err != nil {
   706  		return result, errors.Trace(err)
   707  	}
   708  
   709  	for i, entity := range args.Entities {
   710  		tag, err := names.ParseMachineTag(entity.Tag)
   711  		if err != nil {
   712  			result.Results[i].Error = common.ServerError(err)
   713  			continue
   714  		}
   715  		// The auth function (canAccess) checks that the machine is a
   716  		// top level machine (we filter those out next) or that the
   717  		// machine has the host as a parent.
   718  		container, err := p.getMachine(canAccess, tag)
   719  		if err != nil {
   720  			result.Results[i].Error = common.ServerError(err)
   721  			continue
   722  		} else if !container.IsContainer() {
   723  			err = errors.Errorf("cannot prepare network config for %q: not a container", tag)
   724  			result.Results[i].Error = common.ServerError(err)
   725  			continue
   726  		} else if ciid, cerr := container.InstanceId(); maintain == true && cerr == nil {
   727  			// Since we want to configure and create NICs on the
   728  			// container before it starts, it must also be not
   729  			// provisioned yet.
   730  			err = errors.Errorf("container %q already provisioned as %q", container, ciid)
   731  			result.Results[i].Error = common.ServerError(err)
   732  			continue
   733  		} else if cerr != nil && !errors.IsNotProvisioned(cerr) {
   734  			// Any other error needs to be reported.
   735  			result.Results[i].Error = common.ServerError(cerr)
   736  			continue
   737  		}
   738  
   739  		if err := hostMachine.SetContainerLinkLayerDevices(container); err != nil {
   740  			result.Results[i].Error = common.ServerError(err)
   741  			continue
   742  		}
   743  
   744  		containerDevices, err := container.AllLinkLayerDevices()
   745  		if err != nil {
   746  			result.Results[i].Error = common.ServerError(err)
   747  			continue
   748  		}
   749  
   750  		preparedInfo := make([]network.InterfaceInfo, len(containerDevices))
   751  		preparedOK := true
   752  		for j, device := range containerDevices {
   753  			parentDevice, err := device.ParentDevice()
   754  			if err != nil || parentDevice == nil {
   755  				err = errors.Errorf(
   756  					"cannot get parent %q of container device %q: %v",
   757  					device.ParentName(), device.Name(), err,
   758  				)
   759  				result.Results[i].Error = common.ServerError(err)
   760  				preparedOK = false
   761  				break
   762  			}
   763  			parentAddrs, err := parentDevice.Addresses()
   764  			if err != nil {
   765  				result.Results[i].Error = common.ServerError(err)
   766  				preparedOK = false
   767  				break
   768  			}
   769  			if len(parentAddrs) == 0 {
   770  				err = errors.Errorf("host machine device %q has no addresses", parentDevice.Name())
   771  				result.Results[i].Error = common.ServerError(err)
   772  				preparedOK = false
   773  				break
   774  			}
   775  			firstAddress := parentAddrs[0]
   776  			parentDeviceSubnet, err := firstAddress.Subnet()
   777  			if err != nil {
   778  				err = errors.Annotatef(err,
   779  					"cannot get subnet %q used by address %q of host machine device %q",
   780  					firstAddress.SubnetCIDR(), firstAddress.Value(), parentDevice.Name(),
   781  				)
   782  				result.Results[i].Error = common.ServerError(err)
   783  				preparedOK = false
   784  				break
   785  			}
   786  
   787  			info := network.InterfaceInfo{
   788  				InterfaceName:       device.Name(),
   789  				MACAddress:          device.MACAddress(),
   790  				ConfigType:          network.ConfigStatic,
   791  				InterfaceType:       network.InterfaceType(device.Type()),
   792  				NoAutoStart:         !device.IsAutoStart(),
   793  				Disabled:            !device.IsUp(),
   794  				MTU:                 int(device.MTU()),
   795  				CIDR:                parentDeviceSubnet.CIDR(),
   796  				ProviderSubnetId:    parentDeviceSubnet.ProviderId(),
   797  				VLANTag:             parentDeviceSubnet.VLANTag(),
   798  				ParentInterfaceName: parentDevice.Name(),
   799  			}
   800  			logger.Tracef("prepared info for container interface %q: %+v", info.InterfaceName, info)
   801  			preparedOK = true
   802  			preparedInfo[j] = info
   803  		}
   804  
   805  		if !preparedOK {
   806  			// Error result is already set.
   807  			continue
   808  		}
   809  
   810  		allocatedInfo, err := netEnviron.AllocateContainerAddresses(instId, preparedInfo)
   811  		if err != nil {
   812  			result.Results[i].Error = common.ServerError(err)
   813  			continue
   814  		}
   815  		logger.Debugf("got allocated info from provider: %+v", allocatedInfo)
   816  
   817  		allocatedConfig := networkingcommon.NetworkConfigFromInterfaceInfo(allocatedInfo)
   818  		sortedAllocatedConfig := networkingcommon.SortNetworkConfigsByInterfaceName(allocatedConfig)
   819  		logger.Tracef("allocated sorted network config: %+v", sortedAllocatedConfig)
   820  		result.Results[i].Config = sortedAllocatedConfig
   821  	}
   822  	return result, nil
   823  }
   824  
   825  // legacyPrepareOrGetContainerInterfaceInfo optionally allocates an address and
   826  // returns information for configuring networking on a container. It accepts
   827  // container tags as arguments.
   828  func (p *ProvisionerAPI) legacyPrepareOrGetContainerInterfaceInfo(
   829  	args params.Entities,
   830  	provisionContainer bool,
   831  ) (
   832  	params.MachineNetworkConfigResults,
   833  	error,
   834  ) {
   835  	result := params.MachineNetworkConfigResults{
   836  		Results: make([]params.MachineNetworkConfigResult, len(args.Entities)),
   837  	}
   838  
   839  	// Some preparations first.
   840  	environ, host, canAccess, err := p.prepareContainerAccessEnvironment()
   841  	if err != nil {
   842  		return result, errors.Trace(err)
   843  	}
   844  	instId, err := host.InstanceId()
   845  	if err != nil && errors.IsNotProvisioned(err) {
   846  		// If the host machine is not provisioned yet, we have nothing
   847  		// to do. NotProvisionedf will append " not provisioned" to
   848  		// the message.
   849  		err = errors.NotProvisionedf("cannot allocate addresses: host machine %q", host)
   850  		return result, err
   851  	}
   852  	var subnet *state.Subnet
   853  	var subnetInfo network.SubnetInfo
   854  	var interfaceInfo network.InterfaceInfo
   855  	if environs.AddressAllocationEnabled(environ.Config().Type()) {
   856  		// We don't need a subnet unless we need to allocate a static IP.
   857  		subnet, subnetInfo, interfaceInfo, err = p.prepareAllocationNetwork(environ, instId)
   858  		if err != nil {
   859  			return result, errors.Annotate(err, "cannot allocate addresses")
   860  		}
   861  	} else {
   862  		var allInterfaceInfos []network.InterfaceInfo
   863  		allInterfaceInfos, err = environ.NetworkInterfaces(instId)
   864  		if err != nil {
   865  			return result, errors.Annotatef(err, "cannot instance %q interfaces", instId)
   866  		} else if len(allInterfaceInfos) == 0 {
   867  			return result, errors.New("no interfaces available")
   868  		}
   869  		// Currently we only support a single NIC per container, so we only need
   870  		// the information from the host instance's first NIC.
   871  		logger.Tracef("interfaces for instance %q: %v", instId, allInterfaceInfos)
   872  		interfaceInfo = allInterfaceInfos[0]
   873  	}
   874  
   875  	// Loop over the passed container tags.
   876  	for i, entity := range args.Entities {
   877  		tag, err := names.ParseMachineTag(entity.Tag)
   878  		if err != nil {
   879  			result.Results[i].Error = common.ServerError(err)
   880  			continue
   881  		}
   882  
   883  		// The auth function (canAccess) checks that the machine is a
   884  		// top level machine (we filter those out next) or that the
   885  		// machine has the host as a parent.
   886  		container, err := p.getMachine(canAccess, tag)
   887  		if err != nil {
   888  			result.Results[i].Error = common.ServerError(err)
   889  			continue
   890  		} else if !container.IsContainer() {
   891  			err = errors.Errorf("cannot allocate address for %q: not a container", tag)
   892  			result.Results[i].Error = common.ServerError(err)
   893  			continue
   894  		} else if ciid, cerr := container.InstanceId(); provisionContainer == true && cerr == nil {
   895  			// Since we want to configure and create NICs on the
   896  			// container before it starts, it must also be not
   897  			// provisioned yet.
   898  			err = errors.Errorf("container %q already provisioned as %q", container, ciid)
   899  			result.Results[i].Error = common.ServerError(err)
   900  			continue
   901  		} else if cerr != nil && !errors.IsNotProvisioned(cerr) {
   902  			// Any other error needs to be reported.
   903  			result.Results[i].Error = common.ServerError(cerr)
   904  			continue
   905  		}
   906  
   907  		var macAddress string
   908  		var address *state.IPAddress
   909  		if provisionContainer {
   910  			// Allocate and set an address.
   911  			macAddress = generateMACAddress()
   912  			address, err = p.allocateAddress(environ, subnet, host, container, instId, macAddress)
   913  			if err != nil {
   914  				err = errors.Annotatef(err, "failed to allocate an address for %q", container)
   915  				result.Results[i].Error = common.ServerError(err)
   916  				continue
   917  			}
   918  		} else {
   919  			id := container.Id()
   920  			addresses, err := p.st.AllocatedIPAddresses(id)
   921  			if err != nil {
   922  				logger.Warningf("failed to get Id for container %q: %v", tag, err)
   923  				result.Results[i].Error = common.ServerError(err)
   924  				continue
   925  			}
   926  			// TODO(dooferlad): if we get more than 1 address back, we ignore everything after
   927  			// the first. The calling function expects exactly one result though,
   928  			// so we don't appear to have a way of allocating >1 address to a
   929  			// container...
   930  			if len(addresses) != 1 {
   931  				logger.Warningf("got %d addresses for container %q - expected 1: %v", len(addresses), tag, err)
   932  				result.Results[i].Error = common.ServerError(err)
   933  				continue
   934  			}
   935  			address = addresses[0]
   936  			macAddress = address.MACAddress()
   937  		}
   938  
   939  		// Store it on the machine, construct and set an interface result.
   940  		dnsServers := make([]string, len(interfaceInfo.DNSServers))
   941  		for l, dns := range interfaceInfo.DNSServers {
   942  			dnsServers[l] = dns.Value
   943  		}
   944  
   945  		if macAddress == "" {
   946  			macAddress = interfaceInfo.MACAddress
   947  		}
   948  
   949  		interfaceType := string(interfaceInfo.InterfaceType)
   950  		if interfaceType == "" {
   951  			interfaceType = string(network.EthernetInterface)
   952  		}
   953  
   954  		result.Results[i] = params.MachineNetworkConfigResult{
   955  			Config: []params.NetworkConfig{{
   956  				DeviceIndex:      interfaceInfo.DeviceIndex,
   957  				MACAddress:       macAddress,
   958  				CIDR:             subnetInfo.CIDR,
   959  				ProviderId:       string(interfaceInfo.ProviderId),
   960  				ProviderSubnetId: string(subnetInfo.ProviderId),
   961  				VLANTag:          interfaceInfo.VLANTag,
   962  				InterfaceType:    interfaceType,
   963  				InterfaceName:    interfaceInfo.InterfaceName,
   964  				Disabled:         interfaceInfo.Disabled,
   965  				NoAutoStart:      interfaceInfo.NoAutoStart,
   966  				DNSServers:       dnsServers,
   967  				ConfigType:       string(network.ConfigStatic),
   968  				Address:          address.Value(),
   969  				GatewayAddress:   interfaceInfo.GatewayAddress.Value,
   970  			}},
   971  		}
   972  	}
   973  	return result, nil
   974  }
   975  
   976  // prepareContainerAccessEnvironment retrieves the environment, host machine, and access
   977  // for working with containers.
   978  func (p *ProvisionerAPI) prepareContainerAccessEnvironment() (environs.NetworkingEnviron, *state.Machine, common.AuthFunc, error) {
   979  	netEnviron, err := networkingcommon.NetworkingEnvironFromModelConfig(p.st)
   980  	if err != nil {
   981  		return nil, nil, nil, errors.Trace(err)
   982  	}
   983  
   984  	canAccess, err := p.getAuthFunc()
   985  	if err != nil {
   986  		return nil, nil, nil, errors.Annotate(err, "cannot authenticate request")
   987  	}
   988  	hostAuthTag := p.authorizer.GetAuthTag()
   989  	if hostAuthTag == nil {
   990  		return nil, nil, nil, errors.Errorf("authenticated entity tag is nil")
   991  	}
   992  	hostTag, err := names.ParseMachineTag(hostAuthTag.String())
   993  	if err != nil {
   994  		return nil, nil, nil, errors.Trace(err)
   995  	}
   996  	host, err := p.getMachine(canAccess, hostTag)
   997  	if err != nil {
   998  		return nil, nil, nil, errors.Trace(err)
   999  	}
  1000  	return netEnviron, host, canAccess, nil
  1001  }
  1002  
  1003  // prepareAllocationNetwork retrieves the subnet, its info, and the interface info
  1004  // for the allocations.
  1005  func (p *ProvisionerAPI) prepareAllocationNetwork(
  1006  	environ environs.NetworkingEnviron,
  1007  	instId instance.Id,
  1008  ) (
  1009  	*state.Subnet,
  1010  	network.SubnetInfo,
  1011  	network.InterfaceInfo,
  1012  	error,
  1013  ) {
  1014  	var subnetInfo network.SubnetInfo
  1015  	var interfaceInfo network.InterfaceInfo
  1016  
  1017  	interfaces, err := environ.NetworkInterfaces(instId)
  1018  	if err != nil {
  1019  		return nil, subnetInfo, interfaceInfo, errors.Trace(err)
  1020  	} else if len(interfaces) == 0 {
  1021  		return nil, subnetInfo, interfaceInfo, errors.New("no interfaces available")
  1022  	}
  1023  	logger.Tracef("interfaces for instance %q: %v", instId, interfaces)
  1024  
  1025  	subnetSet := make(set.Strings)
  1026  	subnetIds := []network.Id{}
  1027  	subnetIdToInterface := make(map[network.Id]network.InterfaceInfo)
  1028  	for _, iface := range interfaces {
  1029  		if iface.ProviderSubnetId == "" {
  1030  			logger.Debugf("no subnet associated with interface %#v (skipping)", iface)
  1031  			continue
  1032  		} else if iface.Disabled {
  1033  			logger.Debugf("interface %#v disabled (skipping)", iface)
  1034  			continue
  1035  		}
  1036  		if !subnetSet.Contains(string(iface.ProviderSubnetId)) {
  1037  			subnetIds = append(subnetIds, iface.ProviderSubnetId)
  1038  			subnetSet.Add(string(iface.ProviderSubnetId))
  1039  
  1040  			// This means that multiple interfaces on the same subnet will
  1041  			// only appear once.
  1042  			subnetIdToInterface[iface.ProviderSubnetId] = iface
  1043  		}
  1044  	}
  1045  	subnets, err := environ.Subnets(instId, subnetIds)
  1046  	if err != nil {
  1047  		return nil, subnetInfo, interfaceInfo, errors.Trace(err)
  1048  	} else if len(subnets) == 0 {
  1049  		return nil, subnetInfo, interfaceInfo, errors.Errorf("no subnets available")
  1050  	}
  1051  	logger.Tracef("subnets for instance %q: %v", instId, subnets)
  1052  
  1053  	// TODO(mfoord): we need a better strategy for picking a subnet to
  1054  	// allocate an address on. (dimitern): Right now we just pick the
  1055  	// first subnet with allocatable range set. Instead, we should
  1056  	// allocate an address per interface, assuming each interface is
  1057  	// on a subnet with allocatable range set, and skipping those
  1058  	// which do not have a range set.
  1059  	var success bool
  1060  	for _, sub := range subnets {
  1061  		logger.Tracef("trying to allocate a static IP on subnet %q", sub.ProviderId)
  1062  		if sub.AllocatableIPHigh == nil {
  1063  			logger.Tracef("ignoring subnet %q - no allocatable range set", sub.ProviderId)
  1064  			// this subnet has no allocatable IPs
  1065  			continue
  1066  		}
  1067  		if sub.AllocatableIPLow != nil && sub.AllocatableIPLow.To4() == nil {
  1068  			logger.Tracef("ignoring IPv6 subnet %q - allocating IPv6 addresses not yet supported", sub.ProviderId)
  1069  			// Until we change the way we pick addresses, IPv6 subnets with
  1070  			// their *huge* ranges (/64 being the default), there is no point in
  1071  			// allowing such subnets (it won't even work as PickNewAddress()
  1072  			// assumes IPv4 allocatable range anyway).
  1073  			continue
  1074  		}
  1075  		ok, err := environ.SupportsAddressAllocation(sub.ProviderId)
  1076  		if err == nil && ok {
  1077  			subnetInfo = sub
  1078  			interfaceInfo = subnetIdToInterface[sub.ProviderId]
  1079  
  1080  			// Since with addressable containers the host acts like a gateway
  1081  			// for the containers, instead of using the same gateway for the
  1082  			// containers as their host's
  1083  			interfaceInfo.GatewayAddress.Value = interfaceInfo.Address.Value
  1084  
  1085  			success = true
  1086  			break
  1087  		}
  1088  		logger.Tracef(
  1089  			"subnet %q supports address allocation: %v (error: %v)",
  1090  			sub.ProviderId, ok, err,
  1091  		)
  1092  	}
  1093  	if !success {
  1094  		// " not supported" will be appended to the message below.
  1095  		return nil, subnetInfo, interfaceInfo, errors.NotSupportedf(
  1096  			"address allocation on any available subnets is",
  1097  		)
  1098  	}
  1099  	subnet, err := p.createOrFetchStateSubnet(subnetInfo)
  1100  
  1101  	return subnet, subnetInfo, interfaceInfo, nil
  1102  }
  1103  
  1104  // These are defined like this to allow mocking in tests.
  1105  var (
  1106  	allocateAddrTo = func(a *state.IPAddress, m *state.Machine, macAddress string) error {
  1107  		// TODO(mfoord): populate proper interface ID (in state).
  1108  		return a.AllocateTo(m.Id(), "", macAddress)
  1109  	}
  1110  	setAddrsTo = func(a *state.IPAddress, m *state.Machine) error {
  1111  		return m.SetProviderAddresses(a.Address())
  1112  	}
  1113  	setAddrState = func(a *state.IPAddress, st state.AddressState) error {
  1114  		return a.SetState(st)
  1115  	}
  1116  )
  1117  
  1118  // allocateAddress tries to pick an address out of the given subnet and
  1119  // allocates it to the container.
  1120  func (p *ProvisionerAPI) allocateAddress(
  1121  	environ environs.NetworkingEnviron,
  1122  	subnet *state.Subnet,
  1123  	host, container *state.Machine,
  1124  	instId instance.Id,
  1125  	macAddress string,
  1126  ) (*state.IPAddress, error) {
  1127  	hostname := containerHostname(container.Tag())
  1128  
  1129  	if !environs.AddressAllocationEnabled(environ.Config().Type()) {
  1130  		// Even if the address allocation feature flag is not enabled, we might
  1131  		// be running on MAAS 1.8+ with devices support, which we can use to
  1132  		// register containers getting IPs via DHCP. However, most of the usual
  1133  		// allocation code can be bypassed, we just need the parent instance ID
  1134  		// and a MAC address (no subnet or IP address).
  1135  		allocatedAddress := network.Address{}
  1136  		err := environ.AllocateAddress(instId, network.AnySubnet, &allocatedAddress, macAddress, hostname)
  1137  		if err != nil {
  1138  			// Not using MAAS 1.8+ or some other error.
  1139  			return nil, errors.Trace(err)
  1140  		}
  1141  
  1142  		logger.Infof(
  1143  			"allocated address %q on instance %q for container %q",
  1144  			allocatedAddress.String(), instId, hostname,
  1145  		)
  1146  
  1147  		// Add the address to state, so we can look it up later by MAC address.
  1148  		stateAddr, err := p.st.AddIPAddress(allocatedAddress, string(network.AnySubnet))
  1149  		if err != nil {
  1150  			return nil, errors.Annotatef(err, "failed to save address %q", allocatedAddress)
  1151  		}
  1152  
  1153  		err = p.setAllocatedOrRelease(stateAddr, environ, instId, container, network.AnySubnet, macAddress)
  1154  		if err != nil {
  1155  			return nil, errors.Trace(err)
  1156  		}
  1157  
  1158  		return stateAddr, nil
  1159  	}
  1160  
  1161  	subnetId := network.Id(subnet.ProviderId())
  1162  	for {
  1163  		addr, err := subnet.PickNewAddress()
  1164  		if err != nil {
  1165  			return nil, err
  1166  		}
  1167  		netAddr := addr.Address()
  1168  		logger.Tracef("picked new address %q on subnet %q", addr.String(), subnetId)
  1169  		// Attempt to allocate with environ.
  1170  		err = environ.AllocateAddress(instId, subnetId, &netAddr, macAddress, hostname)
  1171  		if err != nil {
  1172  			logger.Warningf(
  1173  				"allocating address %q on instance %q and subnet %q failed: %v (retrying)",
  1174  				addr.String(), instId, subnetId, err,
  1175  			)
  1176  			// It's as good as unavailable for us, so mark it as
  1177  			// such.
  1178  			err = setAddrState(addr, state.AddressStateUnavailable)
  1179  			if err != nil {
  1180  				logger.Warningf(
  1181  					"cannot set address %q to %q: %v (ignoring and retrying)",
  1182  					addr.String(), state.AddressStateUnavailable, err,
  1183  				)
  1184  				continue
  1185  			}
  1186  			logger.Tracef(
  1187  				"setting address %q to %q and retrying",
  1188  				addr.String(), state.AddressStateUnavailable,
  1189  			)
  1190  			continue
  1191  		}
  1192  		logger.Infof(
  1193  			"allocated address %q on instance %q and subnet %q",
  1194  			addr.String(), instId, subnetId,
  1195  		)
  1196  		err = p.setAllocatedOrRelease(addr, environ, instId, container, subnetId, macAddress)
  1197  		if err != nil {
  1198  			// Something went wrong - retry.
  1199  			continue
  1200  		}
  1201  		return addr, nil
  1202  	}
  1203  }
  1204  
  1205  // setAllocatedOrRelease tries to associate the newly allocated
  1206  // address addr with the container. On failure it makes the best
  1207  // effort to cleanup and release addr, logging issues along the way.
  1208  func (p *ProvisionerAPI) setAllocatedOrRelease(
  1209  	addr *state.IPAddress,
  1210  	environ environs.NetworkingEnviron,
  1211  	instId instance.Id,
  1212  	container *state.Machine,
  1213  	subnetId network.Id,
  1214  	macAddress string,
  1215  ) (err error) {
  1216  	defer func() {
  1217  		if errors.Cause(err) == nil {
  1218  			// Success!
  1219  			return
  1220  		}
  1221  		logger.Warningf(
  1222  			"failed to mark address %q as %q to container %q: %v (releasing and retrying)",
  1223  			addr.String(), state.AddressStateAllocated, container, err,
  1224  		)
  1225  		// It's as good as unavailable for us, so mark it as
  1226  		// such.
  1227  		err = setAddrState(addr, state.AddressStateUnavailable)
  1228  		if err != nil {
  1229  			logger.Warningf(
  1230  				"cannot set address %q to %q: %v (ignoring and releasing)",
  1231  				addr.String(), state.AddressStateUnavailable, err,
  1232  			)
  1233  		}
  1234  		err = environ.ReleaseAddress(instId, subnetId, addr.Address(), addr.MACAddress(), "")
  1235  		if err == nil {
  1236  			logger.Infof("address %q released; trying to allocate new", addr.String())
  1237  			return
  1238  		}
  1239  		logger.Warningf(
  1240  			"failed to release address %q on instance %q and subnet %q: %v (ignoring and retrying)",
  1241  			addr.String(), instId, subnetId, err,
  1242  		)
  1243  	}()
  1244  
  1245  	// Any errors returned below will trigger the release/cleanup
  1246  	// steps above.
  1247  	if err = allocateAddrTo(addr, container, macAddress); err != nil {
  1248  		return errors.Trace(err)
  1249  	}
  1250  	if err = setAddrsTo(addr, container); err != nil {
  1251  		return errors.Trace(err)
  1252  	}
  1253  
  1254  	logger.Infof("assigned address %q to container %q", addr.String(), container)
  1255  	return nil
  1256  }
  1257  
  1258  func (p *ProvisionerAPI) createOrFetchStateSubnet(subnetInfo network.SubnetInfo) (*state.Subnet, error) {
  1259  	stateSubnetInfo := state.SubnetInfo{
  1260  		ProviderId:        subnetInfo.ProviderId,
  1261  		CIDR:              subnetInfo.CIDR,
  1262  		VLANTag:           subnetInfo.VLANTag,
  1263  		AllocatableIPHigh: subnetInfo.AllocatableIPHigh.String(),
  1264  		AllocatableIPLow:  subnetInfo.AllocatableIPLow.String(),
  1265  	}
  1266  	subnet, err := p.st.AddSubnet(stateSubnetInfo)
  1267  	if err != nil {
  1268  		if errors.IsAlreadyExists(err) {
  1269  			subnet, err = p.st.Subnet(subnetInfo.CIDR)
  1270  		}
  1271  		if err != nil {
  1272  			return subnet, errors.Trace(err)
  1273  		}
  1274  	}
  1275  	return subnet, nil
  1276  }
  1277  
  1278  // InstanceStatus returns the instance status for each given entity.
  1279  // Only machine tags are accepted.
  1280  func (p *ProvisionerAPI) InstanceStatus(args params.Entities) (params.StatusResults, error) {
  1281  	result := params.StatusResults{
  1282  		Results: make([]params.StatusResult, len(args.Entities)),
  1283  	}
  1284  	canAccess, err := p.getAuthFunc()
  1285  	if err != nil {
  1286  		logger.Errorf("failed to get an authorisation function: %v", err)
  1287  		return result, errors.Trace(err)
  1288  	}
  1289  	for i, arg := range args.Entities {
  1290  		mTag, err := names.ParseMachineTag(arg.Tag)
  1291  		if err != nil {
  1292  			result.Results[i].Error = common.ServerError(err)
  1293  			continue
  1294  		}
  1295  		machine, err := p.getMachine(canAccess, mTag)
  1296  		if err == nil {
  1297  			var statusInfo status.StatusInfo
  1298  			statusInfo, err = machine.InstanceStatus()
  1299  			result.Results[i].Status = statusInfo.Status
  1300  			result.Results[i].Info = statusInfo.Message
  1301  			result.Results[i].Data = statusInfo.Data
  1302  			result.Results[i].Since = statusInfo.Since
  1303  		}
  1304  		result.Results[i].Error = common.ServerError(err)
  1305  	}
  1306  	return result, nil
  1307  }
  1308  
  1309  // SetInstanceStatus updates the instance status for each given
  1310  // entity. Only machine tags are accepted.
  1311  func (p *ProvisionerAPI) SetInstanceStatus(args params.SetStatus) (params.ErrorResults, error) {
  1312  	result := params.ErrorResults{
  1313  		Results: make([]params.ErrorResult, len(args.Entities)),
  1314  	}
  1315  	canAccess, err := p.getAuthFunc()
  1316  	if err != nil {
  1317  		logger.Errorf("failed to get an authorisation function: %v", err)
  1318  		return result, errors.Trace(err)
  1319  	}
  1320  	for i, arg := range args.Entities {
  1321  		mTag, err := names.ParseMachineTag(arg.Tag)
  1322  		if err != nil {
  1323  			result.Results[i].Error = common.ServerError(err)
  1324  			continue
  1325  		}
  1326  		machine, err := p.getMachine(canAccess, mTag)
  1327  		if err == nil {
  1328  			err = machine.SetInstanceStatus(arg.Status, arg.Info, arg.Data)
  1329  		}
  1330  		result.Results[i].Error = common.ServerError(err)
  1331  	}
  1332  	return result, nil
  1333  }