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