github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/api/provisioner/machine.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  	"fmt"
     8  
     9  	"github.com/juju/names"
    10  
    11  	"github.com/juju/juju/api/watcher"
    12  	"github.com/juju/juju/apiserver/params"
    13  	"github.com/juju/juju/instance"
    14  )
    15  
    16  // Machine represents a juju machine as seen by the provisioner worker.
    17  type Machine struct {
    18  	tag  names.MachineTag
    19  	life params.Life
    20  	st   *State
    21  }
    22  
    23  // Tag returns the machine's tag.
    24  func (m *Machine) Tag() names.Tag {
    25  	return m.tag
    26  }
    27  
    28  // Id returns the machine id.
    29  func (m *Machine) Id() string {
    30  	return m.tag.Id()
    31  }
    32  
    33  // String returns the machine as a string.
    34  func (m *Machine) String() string {
    35  	return m.Id()
    36  }
    37  
    38  // Life returns the machine's lifecycle value.
    39  func (m *Machine) Life() params.Life {
    40  	return m.life
    41  }
    42  
    43  // Refresh updates the cached local copy of the machine's data.
    44  func (m *Machine) Refresh() error {
    45  	life, err := m.st.machineLife(m.tag)
    46  	if err != nil {
    47  		return err
    48  	}
    49  	m.life = life
    50  	return nil
    51  }
    52  
    53  // ProvisioningInfo returns the information required to provision a machine.
    54  func (m *Machine) ProvisioningInfo() (*params.ProvisioningInfo, error) {
    55  	var results params.ProvisioningInfoResults
    56  	args := params.Entities{Entities: []params.Entity{{m.tag.String()}}}
    57  	err := m.st.facade.FacadeCall("ProvisioningInfo", args, &results)
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  	if len(results.Results) != 1 {
    62  		return nil, fmt.Errorf("expected 1 result, got %d", len(results.Results))
    63  	}
    64  	result := results.Results[0]
    65  	if result.Error != nil {
    66  		return nil, result.Error
    67  	}
    68  	return result.Result, nil
    69  }
    70  
    71  // SetStatus sets the status of the machine.
    72  func (m *Machine) SetStatus(status params.Status, info string, data map[string]interface{}) error {
    73  	var result params.ErrorResults
    74  	args := params.SetStatus{
    75  		Entities: []params.EntityStatusArgs{
    76  			{Tag: m.tag.String(), Status: status, Info: info, Data: data},
    77  		},
    78  	}
    79  	err := m.st.facade.FacadeCall("SetStatus", args, &result)
    80  	if err != nil {
    81  		return err
    82  	}
    83  	return result.OneError()
    84  }
    85  
    86  // Status returns the status of the machine.
    87  func (m *Machine) Status() (params.Status, string, error) {
    88  	var results params.StatusResults
    89  	args := params.Entities{
    90  		Entities: []params.Entity{{Tag: m.tag.String()}},
    91  	}
    92  	err := m.st.facade.FacadeCall("Status", args, &results)
    93  	if err != nil {
    94  		return "", "", err
    95  	}
    96  	if len(results.Results) != 1 {
    97  		return "", "", fmt.Errorf("expected 1 result, got %d", len(results.Results))
    98  	}
    99  	result := results.Results[0]
   100  	if result.Error != nil {
   101  		return "", "", result.Error
   102  	}
   103  	return result.Status, result.Info, nil
   104  }
   105  
   106  // EnsureDead sets the machine lifecycle to Dead if it is Alive or
   107  // Dying. It does nothing otherwise.
   108  func (m *Machine) EnsureDead() error {
   109  	var result params.ErrorResults
   110  	args := params.Entities{
   111  		Entities: []params.Entity{{Tag: m.tag.String()}},
   112  	}
   113  	err := m.st.facade.FacadeCall("EnsureDead", args, &result)
   114  	if err != nil {
   115  		return err
   116  	}
   117  	return result.OneError()
   118  }
   119  
   120  // Remove removes the machine from state. It will fail if the machine
   121  // is not Dead.
   122  func (m *Machine) Remove() error {
   123  	var result params.ErrorResults
   124  	args := params.Entities{
   125  		Entities: []params.Entity{{Tag: m.tag.String()}},
   126  	}
   127  	err := m.st.facade.FacadeCall("Remove", args, &result)
   128  	if err != nil {
   129  		return err
   130  	}
   131  	return result.OneError()
   132  }
   133  
   134  // Series returns the operating system series running on the machine.
   135  //
   136  // NOTE: Unlike state.Machine.Series(), this method returns an error
   137  // as well, because it needs to do an API call.
   138  func (m *Machine) Series() (string, error) {
   139  	var results params.StringResults
   140  	args := params.Entities{
   141  		Entities: []params.Entity{{Tag: m.tag.String()}},
   142  	}
   143  	err := m.st.facade.FacadeCall("Series", args, &results)
   144  	if err != nil {
   145  		return "", err
   146  	}
   147  	if len(results.Results) != 1 {
   148  		return "", fmt.Errorf("expected 1 result, got %d", len(results.Results))
   149  	}
   150  	result := results.Results[0]
   151  	if result.Error != nil {
   152  		return "", result.Error
   153  	}
   154  	return result.Result, nil
   155  }
   156  
   157  // DistributionGroup returns a slice of instance.Ids
   158  // that belong to the same distribution group as this
   159  // Machine. The provisioner may use this information
   160  // to distribute instances for high availability.
   161  func (m *Machine) DistributionGroup() ([]instance.Id, error) {
   162  	var results params.DistributionGroupResults
   163  	args := params.Entities{
   164  		Entities: []params.Entity{{Tag: m.tag.String()}},
   165  	}
   166  	err := m.st.facade.FacadeCall("DistributionGroup", args, &results)
   167  	if err != nil {
   168  		return nil, err
   169  	}
   170  	if len(results.Results) != 1 {
   171  		return nil, fmt.Errorf("expected 1 result, got %d", len(results.Results))
   172  	}
   173  	result := results.Results[0]
   174  	if result.Error != nil {
   175  		return nil, result.Error
   176  	}
   177  	return result.Result, nil
   178  }
   179  
   180  // SetInstanceInfo sets the provider specific instance id, nonce,
   181  // metadata, networks and interfaces for this machine. Once set, the
   182  // instance id cannot be changed.
   183  func (m *Machine) SetInstanceInfo(
   184  	id instance.Id, nonce string, characteristics *instance.HardwareCharacteristics,
   185  	networks []params.Network, interfaces []params.NetworkInterface, volumes []params.Volume,
   186  	volumeAttachments map[string]params.VolumeAttachmentInfo,
   187  ) error {
   188  	var result params.ErrorResults
   189  	args := params.InstancesInfo{
   190  		Machines: []params.InstanceInfo{{
   191  			Tag:               m.tag.String(),
   192  			InstanceId:        id,
   193  			Nonce:             nonce,
   194  			Characteristics:   characteristics,
   195  			Networks:          networks,
   196  			Interfaces:        interfaces,
   197  			Volumes:           volumes,
   198  			VolumeAttachments: volumeAttachments,
   199  		}},
   200  	}
   201  	err := m.st.facade.FacadeCall("SetInstanceInfo", args, &result)
   202  	if err != nil {
   203  		return err
   204  	}
   205  	return result.OneError()
   206  }
   207  
   208  // InstanceId returns the provider specific instance id for the
   209  // machine or an CodeNotProvisioned error, if not set.
   210  func (m *Machine) InstanceId() (instance.Id, error) {
   211  	var results params.StringResults
   212  	args := params.Entities{
   213  		Entities: []params.Entity{{Tag: m.tag.String()}},
   214  	}
   215  	err := m.st.facade.FacadeCall("InstanceId", args, &results)
   216  	if err != nil {
   217  		return "", err
   218  	}
   219  	if len(results.Results) != 1 {
   220  		return "", fmt.Errorf("expected 1 result, got %d", len(results.Results))
   221  	}
   222  	result := results.Results[0]
   223  	if result.Error != nil {
   224  		return "", result.Error
   225  	}
   226  	return instance.Id(result.Result), nil
   227  }
   228  
   229  // SetPassword sets the machine's password.
   230  func (m *Machine) SetPassword(password string) error {
   231  	var result params.ErrorResults
   232  	args := params.EntityPasswords{
   233  		Changes: []params.EntityPassword{
   234  			{Tag: m.tag.String(), Password: password},
   235  		},
   236  	}
   237  	err := m.st.facade.FacadeCall("SetPasswords", args, &result)
   238  	if err != nil {
   239  		return err
   240  	}
   241  	return result.OneError()
   242  }
   243  
   244  // WatchContainers returns a StringsWatcher that notifies of changes
   245  // to the lifecycles of containers of the specified type on the machine.
   246  func (m *Machine) WatchContainers(ctype instance.ContainerType) (watcher.StringsWatcher, error) {
   247  	if string(ctype) == "" {
   248  		return nil, fmt.Errorf("container type must be specified")
   249  	}
   250  	supported := false
   251  	for _, c := range instance.ContainerTypes {
   252  		if ctype == c {
   253  			supported = true
   254  			break
   255  		}
   256  	}
   257  	if !supported {
   258  		return nil, fmt.Errorf("unsupported container type %q", ctype)
   259  	}
   260  	var results params.StringsWatchResults
   261  	args := params.WatchContainers{
   262  		Params: []params.WatchContainer{
   263  			{MachineTag: m.tag.String(), ContainerType: string(ctype)},
   264  		},
   265  	}
   266  	err := m.st.facade.FacadeCall("WatchContainers", args, &results)
   267  	if err != nil {
   268  		return nil, err
   269  	}
   270  	if len(results.Results) != 1 {
   271  		return nil, fmt.Errorf("expected 1 result, got %d", len(results.Results))
   272  	}
   273  	result := results.Results[0]
   274  	if result.Error != nil {
   275  		return nil, result.Error
   276  	}
   277  	w := watcher.NewStringsWatcher(m.st.facade.RawAPICaller(), result)
   278  	return w, nil
   279  }
   280  
   281  // WatchAllContainers returns a StringsWatcher that notifies of changes
   282  // to the lifecycles of all containers on the machine.
   283  func (m *Machine) WatchAllContainers() (watcher.StringsWatcher, error) {
   284  	var results params.StringsWatchResults
   285  	args := params.WatchContainers{
   286  		Params: []params.WatchContainer{
   287  			{MachineTag: m.tag.String()},
   288  		},
   289  	}
   290  	err := m.st.facade.FacadeCall("WatchContainers", args, &results)
   291  	if err != nil {
   292  		return nil, err
   293  	}
   294  	if len(results.Results) != 1 {
   295  		return nil, fmt.Errorf("expected 1 result, got %d", len(results.Results))
   296  	}
   297  	result := results.Results[0]
   298  	if result.Error != nil {
   299  		return nil, result.Error
   300  	}
   301  	w := watcher.NewStringsWatcher(m.st.facade.RawAPICaller(), result)
   302  	return w, nil
   303  }
   304  
   305  // SetSupportedContainers updates the list of containers supported by this machine.
   306  func (m *Machine) SetSupportedContainers(containerTypes ...instance.ContainerType) error {
   307  	var results params.ErrorResults
   308  	args := params.MachineContainersParams{
   309  		Params: []params.MachineContainers{
   310  			{MachineTag: m.tag.String(), ContainerTypes: containerTypes},
   311  		},
   312  	}
   313  	err := m.st.facade.FacadeCall("SetSupportedContainers", args, &results)
   314  	if err != nil {
   315  		return err
   316  	}
   317  	if len(results.Results) != 1 {
   318  		return fmt.Errorf("expected 1 result, got %d", len(results.Results))
   319  	}
   320  	apiError := results.Results[0].Error
   321  	if apiError != nil {
   322  		return apiError
   323  	}
   324  	return nil
   325  }
   326  
   327  // SupportsNoContainers records the fact that this machine doesn't support any containers.
   328  func (m *Machine) SupportsNoContainers() error {
   329  	return m.SetSupportedContainers([]instance.ContainerType{}...)
   330  }