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