github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/api/provisioner/provisioner.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package provisioner
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/version"
     9  	"gopkg.in/juju/names.v2"
    10  
    11  	"github.com/juju/juju/api/base"
    12  	"github.com/juju/juju/api/common"
    13  	apiwatcher "github.com/juju/juju/api/watcher"
    14  	"github.com/juju/juju/apiserver/params"
    15  	"github.com/juju/juju/core/watcher"
    16  	"github.com/juju/juju/network"
    17  	"github.com/juju/juju/tools"
    18  )
    19  
    20  // State provides access to the Machiner API facade.
    21  type State struct {
    22  	*common.ModelWatcher
    23  	*common.APIAddresser
    24  	*common.ControllerConfigAPI
    25  
    26  	facade base.FacadeCaller
    27  }
    28  
    29  // MachineResult provides a found Machine and any Error related to
    30  // finding it.
    31  type MachineResult struct {
    32  	Machine MachineProvisioner
    33  	Err     *params.Error
    34  }
    35  
    36  // MachineStatusResult provides a found Machine and Status Results
    37  // for it.
    38  type MachineStatusResult struct {
    39  	Machine MachineProvisioner
    40  	Status  params.StatusResult
    41  }
    42  
    43  // DistributionGroupResult provides a slice of machine.Ids in the
    44  // distribution group and any Error related to finding it.
    45  type DistributionGroupResult struct {
    46  	MachineIds []string
    47  	Err        *params.Error
    48  }
    49  
    50  // LXDProfileResult provides a charm.LXDProfile, adding the name.
    51  type LXDProfileResult struct {
    52  	Config      map[string]string            `json:"config" yaml:"config"`
    53  	Description string                       `json:"description" yaml:"description"`
    54  	Devices     map[string]map[string]string `json:"devices" yaml:"devices"`
    55  	Name        string                       `json:"name" yaml:"name"`
    56  }
    57  
    58  const provisionerFacade = "Provisioner"
    59  
    60  // NewState creates a new provisioner facade using the input caller.
    61  func NewState(caller base.APICaller) *State {
    62  	facadeCaller := base.NewFacadeCaller(caller, provisionerFacade)
    63  	return NewStateFromFacade(facadeCaller)
    64  }
    65  
    66  // NewStateFromFacade creates a new provisioner facade using the input
    67  // facade caller.
    68  func NewStateFromFacade(facadeCaller base.FacadeCaller) *State {
    69  	return &State{
    70  		ModelWatcher:        common.NewModelWatcher(facadeCaller),
    71  		APIAddresser:        common.NewAPIAddresser(facadeCaller),
    72  		ControllerConfigAPI: common.NewControllerConfig(facadeCaller),
    73  		facade:              facadeCaller,
    74  	}
    75  }
    76  
    77  // machineLife requests the lifecycle of the given machine from the server.
    78  func (st *State) machineLife(tag names.MachineTag) (params.Life, error) {
    79  	return common.OneLife(st.facade, tag)
    80  }
    81  
    82  // Machine provides access to methods of a state.Machine through the facade
    83  // for the given tags.
    84  func (st *State) Machines(tags ...names.MachineTag) ([]MachineResult, error) {
    85  	lenTags := len(tags)
    86  	genericTags := make([]names.Tag, lenTags)
    87  	for i, t := range tags {
    88  		genericTags[i] = t
    89  	}
    90  	result, err := common.Life(st.facade, genericTags)
    91  	if err != nil {
    92  		return []MachineResult{}, err
    93  	}
    94  	machines := make([]MachineResult, lenTags)
    95  	for i, r := range result {
    96  		if r.Error == nil {
    97  			machines[i].Machine = &Machine{
    98  				tag:  tags[i],
    99  				life: r.Life,
   100  				st:   st,
   101  			}
   102  		} else {
   103  			machines[i].Err = r.Error
   104  		}
   105  	}
   106  	return machines, nil
   107  }
   108  
   109  // WatchModelMachines returns a StringsWatcher that notifies of
   110  // changes to the lifecycles of the machines (but not containers) in
   111  // the current model.
   112  func (st *State) WatchModelMachines() (watcher.StringsWatcher, error) {
   113  	var result params.StringsWatchResult
   114  	err := st.facade.FacadeCall("WatchModelMachines", nil, &result)
   115  	if err != nil {
   116  		return nil, err
   117  	}
   118  	if err := result.Error; err != nil {
   119  		return nil, result.Error
   120  	}
   121  	w := apiwatcher.NewStringsWatcher(st.facade.RawAPICaller(), result)
   122  	return w, nil
   123  }
   124  
   125  func (st *State) WatchMachineErrorRetry() (watcher.NotifyWatcher, error) {
   126  	var result params.NotifyWatchResult
   127  	err := st.facade.FacadeCall("WatchMachineErrorRetry", nil, &result)
   128  	if err != nil {
   129  		return nil, err
   130  	}
   131  	if err := result.Error; err != nil {
   132  		return nil, result.Error
   133  	}
   134  	w := apiwatcher.NewNotifyWatcher(st.facade.RawAPICaller(), result)
   135  	return w, nil
   136  }
   137  
   138  // WatchModelMachinesCharmProfiles returns a StringsWatcher that notifies of
   139  // changes to the upgrade charm profile charm url for all non container machines
   140  // in the current model.
   141  func (st *State) WatchModelMachinesCharmProfiles() (watcher.StringsWatcher, error) {
   142  	var result params.StringsWatchResult
   143  	err := st.facade.FacadeCall("WatchModelMachinesCharmProfiles", nil, &result)
   144  	if err != nil {
   145  		return nil, err
   146  	}
   147  	if err := result.Error; err != nil {
   148  		return nil, result.Error
   149  	}
   150  	w := apiwatcher.NewStringsWatcher(st.facade.RawAPICaller(), result)
   151  	return w, nil
   152  }
   153  
   154  // StateAddresses returns the list of addresses used to connect to the state.
   155  func (st *State) StateAddresses() ([]string, error) {
   156  	var result params.StringsResult
   157  	err := st.facade.FacadeCall("StateAddresses", nil, &result)
   158  	if err != nil {
   159  		return nil, err
   160  	}
   161  	return result.Result, nil
   162  }
   163  
   164  // ContainerManagerConfig returns information from the model config that is
   165  // needed for configuring the container manager.
   166  func (st *State) ContainerManagerConfig(args params.ContainerManagerConfigParams) (result params.ContainerManagerConfig, err error) {
   167  	err = st.facade.FacadeCall("ContainerManagerConfig", args, &result)
   168  	return result, err
   169  }
   170  
   171  // ContainerConfig returns information from the model config that is
   172  // needed for container cloud-init.
   173  func (st *State) ContainerConfig() (result params.ContainerConfig, err error) {
   174  	if st.facade.BestAPIVersion() < 6 {
   175  		return st.containerConfigV5()
   176  	}
   177  	err = st.facade.FacadeCall("ContainerConfig", nil, &result)
   178  	return result, err
   179  }
   180  
   181  func (st *State) containerConfigV5() (params.ContainerConfig, error) {
   182  	var result params.ContainerConfigV5
   183  	if err := st.facade.FacadeCall("ContainerConfig", nil, &result); err != nil {
   184  		return params.ContainerConfig{}, err
   185  	}
   186  	return params.ContainerConfig{
   187  		ProviderType:            result.ProviderType,
   188  		AuthorizedKeys:          result.AuthorizedKeys,
   189  		SSLHostnameVerification: result.SSLHostnameVerification,
   190  		LegacyProxy:             result.Proxy,
   191  		AptProxy:                result.AptProxy,
   192  		// JujuProxy is zero value.
   193  		// SnapProxy is zero value,
   194  		AptMirror:                  result.AptMirror,
   195  		CloudInitUserData:          result.CloudInitUserData,
   196  		ContainerInheritProperties: result.ContainerInheritProperties,
   197  		UpdateBehavior:             result.UpdateBehavior,
   198  	}, nil
   199  }
   200  
   201  // MachinesWithTransientErrors returns a slice of machines and corresponding status information
   202  // for those machines which have transient provisioning errors.
   203  func (st *State) MachinesWithTransientErrors() ([]MachineStatusResult, error) {
   204  	var results params.StatusResults
   205  	err := st.facade.FacadeCall("MachinesWithTransientErrors", nil, &results)
   206  	if err != nil {
   207  		return []MachineStatusResult{}, err
   208  	}
   209  	machines := make([]MachineStatusResult, len(results.Results))
   210  	for i, status := range results.Results {
   211  		if status.Error != nil {
   212  			continue
   213  		}
   214  		machines[i].Machine = &Machine{
   215  			tag:  names.NewMachineTag(status.Id),
   216  			life: status.Life,
   217  			st:   st,
   218  		}
   219  		machines[i].Status = status
   220  	}
   221  	return machines, nil
   222  }
   223  
   224  // FindTools returns al ist of tools matching the specified version number and
   225  // series, and, arch. If arch is blank, a default will be used.
   226  func (st *State) FindTools(v version.Number, series string, arch string) (tools.List, error) {
   227  	args := params.FindToolsParams{
   228  		Number:       v,
   229  		Series:       series,
   230  		MajorVersion: -1,
   231  		MinorVersion: -1,
   232  	}
   233  	if arch != "" {
   234  		args.Arch = arch
   235  	}
   236  	var result params.FindToolsResult
   237  	if err := st.facade.FacadeCall("FindTools", args, &result); err != nil {
   238  		return nil, err
   239  	}
   240  	if result.Error != nil {
   241  		return nil, result.Error
   242  	}
   243  	return result.List, nil
   244  }
   245  
   246  // ReleaseContainerAddresses releases a static IP address allocated to a
   247  // container.
   248  func (st *State) ReleaseContainerAddresses(containerTag names.MachineTag) (err error) {
   249  	defer errors.DeferredAnnotatef(&err, "cannot release static addresses for %q", containerTag.Id())
   250  	var result params.ErrorResults
   251  	args := params.Entities{
   252  		Entities: []params.Entity{{Tag: containerTag.String()}},
   253  	}
   254  	if err := st.facade.FacadeCall("ReleaseContainerAddresses", args, &result); err != nil {
   255  		return err
   256  	}
   257  	return result.OneError()
   258  }
   259  
   260  // PrepareContainerInterfaceInfo allocates an address and returns information to
   261  // configure networking for a container. It accepts container tags as arguments.
   262  func (st *State) PrepareContainerInterfaceInfo(containerTag names.MachineTag) ([]network.InterfaceInfo, error) {
   263  	return st.prepareOrGetContainerInterfaceInfo(containerTag, true)
   264  }
   265  
   266  // GetContainerInterfaceInfo returns information to configure networking
   267  // for a container. It accepts container tags as arguments.
   268  func (st *State) GetContainerInterfaceInfo(containerTag names.MachineTag) ([]network.InterfaceInfo, error) {
   269  	return st.prepareOrGetContainerInterfaceInfo(containerTag, false)
   270  }
   271  
   272  // prepareOrGetContainerInterfaceInfo returns the necessary information to
   273  // configure network interfaces of a container with allocated static
   274  // IP addresses.
   275  //
   276  // TODO(dimitern): Before we start using this, we need to rename both
   277  // the method and the network.InterfaceInfo type to be called
   278  // InterfaceConfig.
   279  func (st *State) prepareOrGetContainerInterfaceInfo(
   280  	containerTag names.MachineTag, allocateNewAddress bool) (
   281  	[]network.InterfaceInfo, error) {
   282  	var result params.MachineNetworkConfigResults
   283  	args := params.Entities{
   284  		Entities: []params.Entity{{Tag: containerTag.String()}},
   285  	}
   286  	methodName := ""
   287  	if allocateNewAddress {
   288  		methodName = "PrepareContainerInterfaceInfo"
   289  	} else {
   290  		methodName = "GetContainerInterfaceInfo"
   291  	}
   292  	if err := st.facade.FacadeCall(methodName, args, &result); err != nil {
   293  		return nil, err
   294  	}
   295  	if len(result.Results) != 1 {
   296  		return nil, errors.Errorf("expected 1 result, got %d", len(result.Results))
   297  	}
   298  	if err := result.Results[0].Error; err != nil {
   299  		return nil, err
   300  	}
   301  	machineConf := result.Results[0]
   302  	ifaceInfo := make([]network.InterfaceInfo, len(machineConf.Config))
   303  	for i, cfg := range machineConf.Config {
   304  		routes := make([]network.Route, len(cfg.Routes))
   305  		for j, route := range cfg.Routes {
   306  			routes[j] = network.Route{
   307  				DestinationCIDR: route.DestinationCIDR,
   308  				GatewayIP:       route.GatewayIP,
   309  				Metric:          route.Metric,
   310  			}
   311  		}
   312  		ifaceInfo[i] = network.InterfaceInfo{
   313  			DeviceIndex:         cfg.DeviceIndex,
   314  			MACAddress:          cfg.MACAddress,
   315  			CIDR:                cfg.CIDR,
   316  			MTU:                 cfg.MTU,
   317  			ProviderId:          network.Id(cfg.ProviderId),
   318  			ProviderSubnetId:    network.Id(cfg.ProviderSubnetId),
   319  			ProviderSpaceId:     network.Id(cfg.ProviderSpaceId),
   320  			ProviderVLANId:      network.Id(cfg.ProviderVLANId),
   321  			ProviderAddressId:   network.Id(cfg.ProviderAddressId),
   322  			VLANTag:             cfg.VLANTag,
   323  			InterfaceName:       cfg.InterfaceName,
   324  			ParentInterfaceName: cfg.ParentInterfaceName,
   325  			InterfaceType:       network.InterfaceType(cfg.InterfaceType),
   326  			Disabled:            cfg.Disabled,
   327  			NoAutoStart:         cfg.NoAutoStart,
   328  			ConfigType:          network.InterfaceConfigType(cfg.ConfigType),
   329  			Address:             network.NewAddress(cfg.Address),
   330  			DNSServers:          network.NewAddresses(cfg.DNSServers...),
   331  			DNSSearchDomains:    cfg.DNSSearchDomains,
   332  			GatewayAddress:      network.NewAddress(cfg.GatewayAddress),
   333  			Routes:              routes,
   334  		}
   335  	}
   336  	return ifaceInfo, nil
   337  }
   338  
   339  // SetHostMachineNetworkConfig sets the network configuration of the
   340  // machine with netConfig
   341  func (st *State) SetHostMachineNetworkConfig(hostMachineTag names.MachineTag, netConfig []params.NetworkConfig) error {
   342  	args := params.SetMachineNetworkConfig{
   343  		Tag:    hostMachineTag.String(),
   344  		Config: netConfig,
   345  	}
   346  	err := st.facade.FacadeCall("SetHostMachineNetworkConfig", args, nil)
   347  	if err != nil {
   348  		return errors.Trace(err)
   349  	}
   350  	return nil
   351  }
   352  
   353  func (st *State) HostChangesForContainer(containerTag names.MachineTag) ([]network.DeviceToBridge, int, error) {
   354  	var result params.HostNetworkChangeResults
   355  	args := params.Entities{
   356  		Entities: []params.Entity{{Tag: containerTag.String()}},
   357  	}
   358  	if err := st.facade.FacadeCall("HostChangesForContainers", args, &result); err != nil {
   359  		return nil, 0, err
   360  	}
   361  	if len(result.Results) != 1 {
   362  		return nil, 0, errors.Errorf("expected 1 result, got %d", len(result.Results))
   363  	}
   364  	if err := result.Results[0].Error; err != nil {
   365  		return nil, 0, err
   366  	}
   367  	newBridges := result.Results[0].NewBridges
   368  	res := make([]network.DeviceToBridge, len(newBridges))
   369  	for i, bridgeInfo := range newBridges {
   370  		res[i].BridgeName = bridgeInfo.BridgeName
   371  		res[i].DeviceName = bridgeInfo.HostDeviceName
   372  		res[i].MACAddress = bridgeInfo.MACAddress
   373  	}
   374  	return res, result.Results[0].ReconfigureDelay, nil
   375  }
   376  
   377  // DistributionGroupByMachineId returns a slice of machine.Ids
   378  // that belong to the same distribution group as the given
   379  // Machine. The provisioner may use this information
   380  // to distribute instances for high availability.
   381  func (st *State) DistributionGroupByMachineId(tags ...names.MachineTag) ([]DistributionGroupResult, error) {
   382  	var stringResults params.StringsResults
   383  	entities := make([]params.Entity, len(tags))
   384  	for i, t := range tags {
   385  		entities[i] = params.Entity{Tag: t.String()}
   386  	}
   387  	err := st.facade.FacadeCall("DistributionGroupByMachineId", params.Entities{Entities: entities}, &stringResults)
   388  	if err != nil {
   389  		return []DistributionGroupResult{}, err
   390  	}
   391  	results := make([]DistributionGroupResult, len(tags))
   392  	for i, stringResult := range stringResults.Results {
   393  		results[i] = DistributionGroupResult{MachineIds: stringResult.Result, Err: stringResult.Error}
   394  	}
   395  	return results, nil
   396  }
   397  
   398  // CACert returns the certificate used to validate the API and state connections.
   399  func (a *State) CACert() (string, error) {
   400  	var result params.BytesResult
   401  	err := a.facade.FacadeCall("CACert", nil, &result)
   402  	if err != nil {
   403  		return "", err
   404  	}
   405  	return string(result.Result), nil
   406  }
   407  
   408  // GetContainerProfileInfo returns a slice of ContainerLXDProfile, 1 for each unit's charm
   409  // which contains an lxd-profile.yaml.
   410  func (st *State) GetContainerProfileInfo(containerTag names.MachineTag) ([]*LXDProfileResult, error) {
   411  	var result params.ContainerProfileResults
   412  	args := params.Entities{
   413  		Entities: []params.Entity{{Tag: containerTag.String()}},
   414  	}
   415  	if err := st.facade.FacadeCall("GetContainerProfileInfo", args, &result); err != nil {
   416  		return nil, err
   417  	}
   418  	if len(result.Results) != 1 {
   419  		return nil, errors.Errorf("expected 1 result, got %d", len(result.Results))
   420  	}
   421  	if err := result.Results[0].Error; err != nil {
   422  		return nil, err
   423  	}
   424  	profiles := result.Results[0].LXDProfiles
   425  	var res []*LXDProfileResult
   426  	for _, p := range profiles {
   427  		if p == nil {
   428  			continue
   429  		}
   430  		res = append(res, &LXDProfileResult{
   431  			Config:      p.Profile.Config,
   432  			Description: p.Profile.Description,
   433  			Devices:     p.Profile.Devices,
   434  			Name:        p.Name,
   435  		})
   436  	}
   437  	return res, nil
   438  }