github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/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/network"
    16  	"github.com/juju/juju/tools"
    17  	"github.com/juju/juju/watcher"
    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  const provisionerFacade = "Provisioner"
    30  
    31  // NewState creates a new client-side Machiner facade.
    32  func NewState(caller base.APICaller) *State {
    33  	facadeCaller := base.NewFacadeCaller(caller, provisionerFacade)
    34  	return &State{
    35  		ModelWatcher:        common.NewModelWatcher(facadeCaller),
    36  		APIAddresser:        common.NewAPIAddresser(facadeCaller),
    37  		ControllerConfigAPI: common.NewControllerConfig(facadeCaller),
    38  		facade:              facadeCaller,
    39  	}
    40  }
    41  
    42  // machineLife requests the lifecycle of the given machine from the server.
    43  func (st *State) machineLife(tag names.MachineTag) (params.Life, error) {
    44  	return common.Life(st.facade, tag)
    45  }
    46  
    47  // Machine provides access to methods of a state.Machine through the facade.
    48  func (st *State) Machine(tag names.MachineTag) (*Machine, error) {
    49  	life, err := st.machineLife(tag)
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  	return &Machine{
    54  		tag:  tag,
    55  		life: life,
    56  		st:   st,
    57  	}, nil
    58  }
    59  
    60  // WatchModelMachines returns a StringsWatcher that notifies of
    61  // changes to the lifecycles of the machines (but not containers) in
    62  // the current model.
    63  func (st *State) WatchModelMachines() (watcher.StringsWatcher, error) {
    64  	var result params.StringsWatchResult
    65  	err := st.facade.FacadeCall("WatchModelMachines", nil, &result)
    66  	if err != nil {
    67  		return nil, err
    68  	}
    69  	if err := result.Error; err != nil {
    70  		return nil, result.Error
    71  	}
    72  	w := apiwatcher.NewStringsWatcher(st.facade.RawAPICaller(), result)
    73  	return w, nil
    74  }
    75  
    76  func (st *State) WatchMachineErrorRetry() (watcher.NotifyWatcher, error) {
    77  	var result params.NotifyWatchResult
    78  	err := st.facade.FacadeCall("WatchMachineErrorRetry", nil, &result)
    79  	if err != nil {
    80  		return nil, err
    81  	}
    82  	if err := result.Error; err != nil {
    83  		return nil, result.Error
    84  	}
    85  	w := apiwatcher.NewNotifyWatcher(st.facade.RawAPICaller(), result)
    86  	return w, nil
    87  }
    88  
    89  // StateAddresses returns the list of addresses used to connect to the state.
    90  func (st *State) StateAddresses() ([]string, error) {
    91  	var result params.StringsResult
    92  	err := st.facade.FacadeCall("StateAddresses", nil, &result)
    93  	if err != nil {
    94  		return nil, err
    95  	}
    96  	return result.Result, nil
    97  }
    98  
    99  // ContainerManagerConfig returns information from the model config that is
   100  // needed for configuring the container manager.
   101  func (st *State) ContainerManagerConfig(args params.ContainerManagerConfigParams) (result params.ContainerManagerConfig, err error) {
   102  	err = st.facade.FacadeCall("ContainerManagerConfig", args, &result)
   103  	return result, err
   104  }
   105  
   106  // ContainerConfig returns information from the model config that is
   107  // needed for container cloud-init.
   108  func (st *State) ContainerConfig() (result params.ContainerConfig, err error) {
   109  	err = st.facade.FacadeCall("ContainerConfig", nil, &result)
   110  	return result, err
   111  }
   112  
   113  // MachinesWithTransientErrors returns a slice of machines and corresponding status information
   114  // for those machines which have transient provisioning errors.
   115  func (st *State) MachinesWithTransientErrors() ([]*Machine, []params.StatusResult, error) {
   116  	var results params.StatusResults
   117  	err := st.facade.FacadeCall("MachinesWithTransientErrors", nil, &results)
   118  	if err != nil {
   119  		return nil, nil, err
   120  	}
   121  	machines := make([]*Machine, len(results.Results))
   122  	for i, status := range results.Results {
   123  		if status.Error != nil {
   124  			continue
   125  		}
   126  		machines[i] = &Machine{
   127  			tag:  names.NewMachineTag(status.Id),
   128  			life: status.Life,
   129  			st:   st,
   130  		}
   131  	}
   132  	return machines, results.Results, nil
   133  }
   134  
   135  // FindTools returns al ist of tools matching the specified version number and
   136  // series, and, arch. If arch is blank, a default will be used.
   137  func (st *State) FindTools(v version.Number, series string, arch string) (tools.List, error) {
   138  	args := params.FindToolsParams{
   139  		Number:       v,
   140  		Series:       series,
   141  		MajorVersion: -1,
   142  		MinorVersion: -1,
   143  	}
   144  	if arch != "" {
   145  		args.Arch = arch
   146  	}
   147  	var result params.FindToolsResult
   148  	if err := st.facade.FacadeCall("FindTools", args, &result); err != nil {
   149  		return nil, err
   150  	}
   151  	if result.Error != nil {
   152  		return nil, result.Error
   153  	}
   154  	return result.List, nil
   155  }
   156  
   157  // ReleaseContainerAddresses releases a static IP address allocated to a
   158  // container.
   159  func (st *State) ReleaseContainerAddresses(containerTag names.MachineTag) (err error) {
   160  	defer errors.DeferredAnnotatef(&err, "cannot release static addresses for %q", containerTag.Id())
   161  	var result params.ErrorResults
   162  	args := params.Entities{
   163  		Entities: []params.Entity{{Tag: containerTag.String()}},
   164  	}
   165  	if err := st.facade.FacadeCall("ReleaseContainerAddresses", args, &result); err != nil {
   166  		return err
   167  	}
   168  	return result.OneError()
   169  }
   170  
   171  // PrepareContainerInterfaceInfo allocates an address and returns information to
   172  // configure networking for a container. It accepts container tags as arguments.
   173  func (st *State) PrepareContainerInterfaceInfo(containerTag names.MachineTag) ([]network.InterfaceInfo, error) {
   174  	return st.prepareOrGetContainerInterfaceInfo(containerTag, true)
   175  }
   176  
   177  // GetContainerInterfaceInfo returns information to configure networking
   178  // for a container. It accepts container tags as arguments.
   179  func (st *State) GetContainerInterfaceInfo(containerTag names.MachineTag) ([]network.InterfaceInfo, error) {
   180  	return st.prepareOrGetContainerInterfaceInfo(containerTag, false)
   181  }
   182  
   183  // prepareOrGetContainerInterfaceInfo returns the necessary information to
   184  // configure network interfaces of a container with allocated static
   185  // IP addresses.
   186  //
   187  // TODO(dimitern): Before we start using this, we need to rename both
   188  // the method and the network.InterfaceInfo type to be called
   189  // InterfaceConfig.
   190  func (st *State) prepareOrGetContainerInterfaceInfo(
   191  	containerTag names.MachineTag, allocateNewAddress bool) (
   192  	[]network.InterfaceInfo, error) {
   193  	var result params.MachineNetworkConfigResults
   194  	args := params.Entities{
   195  		Entities: []params.Entity{{Tag: containerTag.String()}},
   196  	}
   197  	facadeName := ""
   198  	if allocateNewAddress {
   199  		facadeName = "PrepareContainerInterfaceInfo"
   200  	} else {
   201  		facadeName = "GetContainerInterfaceInfo"
   202  	}
   203  	if err := st.facade.FacadeCall(facadeName, args, &result); err != nil {
   204  		return nil, err
   205  	}
   206  	if len(result.Results) != 1 {
   207  		return nil, errors.Errorf("expected 1 result, got %d", len(result.Results))
   208  	}
   209  	if err := result.Results[0].Error; err != nil {
   210  		return nil, err
   211  	}
   212  	ifaceInfo := make([]network.InterfaceInfo, len(result.Results[0].Config))
   213  	for i, cfg := range result.Results[0].Config {
   214  		ifaceInfo[i] = network.InterfaceInfo{
   215  			DeviceIndex:         cfg.DeviceIndex,
   216  			MACAddress:          cfg.MACAddress,
   217  			CIDR:                cfg.CIDR,
   218  			MTU:                 cfg.MTU,
   219  			ProviderId:          network.Id(cfg.ProviderId),
   220  			ProviderSubnetId:    network.Id(cfg.ProviderSubnetId),
   221  			ProviderSpaceId:     network.Id(cfg.ProviderSpaceId),
   222  			ProviderVLANId:      network.Id(cfg.ProviderVLANId),
   223  			ProviderAddressId:   network.Id(cfg.ProviderAddressId),
   224  			VLANTag:             cfg.VLANTag,
   225  			InterfaceName:       cfg.InterfaceName,
   226  			ParentInterfaceName: cfg.ParentInterfaceName,
   227  			InterfaceType:       network.InterfaceType(cfg.InterfaceType),
   228  			Disabled:            cfg.Disabled,
   229  			NoAutoStart:         cfg.NoAutoStart,
   230  			ConfigType:          network.InterfaceConfigType(cfg.ConfigType),
   231  			Address:             network.NewAddress(cfg.Address),
   232  			DNSServers:          network.NewAddresses(cfg.DNSServers...),
   233  			DNSSearchDomains:    cfg.DNSSearchDomains,
   234  			GatewayAddress:      network.NewAddress(cfg.GatewayAddress),
   235  		}
   236  	}
   237  	return ifaceInfo, nil
   238  }