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