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