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