github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/api/upgradeseries/upgradeseries.go (about)

     1  // Copyright 2018 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package upgradeseries
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"gopkg.in/juju/names.v2"
     9  
    10  	"github.com/juju/juju/api/base"
    11  	"github.com/juju/juju/api/common"
    12  	"github.com/juju/juju/apiserver/params"
    13  	"github.com/juju/juju/core/model"
    14  )
    15  
    16  const upgradeSeriesFacade = "UpgradeSeries"
    17  
    18  // Client provides access to the UpgradeSeries API facade.
    19  type Client struct {
    20  	*common.UpgradeSeriesAPI
    21  	*common.LeadershipPinningAPI
    22  
    23  	facade base.FacadeCaller
    24  	// authTag contains the authenticated unit/machine tag.
    25  	authTag names.Tag
    26  }
    27  
    28  // NewClient Constructs an API caller.
    29  func NewClient(caller base.APICaller, authTag names.Tag) *Client {
    30  	facadeCaller := base.NewFacadeCaller(
    31  		caller,
    32  		upgradeSeriesFacade,
    33  	)
    34  	return &Client{
    35  		facade:               facadeCaller,
    36  		authTag:              authTag,
    37  		UpgradeSeriesAPI:     common.NewUpgradeSeriesAPI(facadeCaller, authTag),
    38  		LeadershipPinningAPI: common.NewLeadershipPinningAPIFromFacade(facadeCaller),
    39  	}
    40  }
    41  
    42  // Machine status retrieves the machine status from remote state.
    43  func (s *Client) MachineStatus() (model.UpgradeSeriesStatus, error) {
    44  	var results params.UpgradeSeriesStatusResults
    45  	args := params.Entities{
    46  		Entities: []params.Entity{{Tag: s.authTag.String()}},
    47  	}
    48  
    49  	err := s.facade.FacadeCall("MachineStatus", args, &results)
    50  	if err != nil {
    51  		return "", errors.Trace(err)
    52  	}
    53  	if len(results.Results) != 1 {
    54  		return "", errors.Errorf("expected 1 result, got %d", len(results.Results))
    55  	}
    56  
    57  	r := results.Results[0]
    58  	if r.Error == nil {
    59  		return r.Status, nil
    60  	}
    61  
    62  	if params.IsCodeNotFound(r.Error) {
    63  		return "", errors.NewNotFound(r.Error, "")
    64  	}
    65  	return "", errors.Trace(r.Error)
    66  }
    67  
    68  func (s *Client) TargetSeries() (string, error) {
    69  	var results params.StringResults
    70  	args := params.Entities{
    71  		Entities: []params.Entity{{Tag: s.authTag.String()}},
    72  	}
    73  
    74  	err := s.facade.FacadeCall("TargetSeries", args, &results)
    75  	if err != nil {
    76  		return "", errors.Trace(err)
    77  	}
    78  	if len(results.Results) != 1 {
    79  		return "", errors.Errorf("expected 1 result, got %d", len(results.Results))
    80  	}
    81  
    82  	r := results.Results[0]
    83  	if r.Error == nil {
    84  		return r.Result, nil
    85  	}
    86  
    87  	if params.IsCodeNotFound(r.Error) {
    88  		return "", errors.NewNotFound(r.Error, "")
    89  	}
    90  	return "", errors.Trace(r.Error)
    91  }
    92  
    93  // UnitsPrepared returns the units running on this machine that have
    94  // completed their upgrade-series preparation, and are ready to be stopped and
    95  // have their unit agent services converted for the target series.
    96  func (s *Client) UnitsPrepared() ([]names.UnitTag, error) {
    97  	units, err := s.unitsInState("UnitsPrepared")
    98  	return units, errors.Trace(err)
    99  }
   100  
   101  // UnitsCompleted returns the units running on this machine that have completed
   102  // the upgrade-series workflow and are in their normal running state.
   103  func (s *Client) UnitsCompleted() ([]names.UnitTag, error) {
   104  	units, err := s.unitsInState("UnitsCompleted")
   105  	return units, errors.Trace(err)
   106  }
   107  
   108  func (s *Client) unitsInState(facadeMethod string) ([]names.UnitTag, error) {
   109  	var results params.EntitiesResults
   110  	args := params.Entities{
   111  		Entities: []params.Entity{{Tag: s.authTag.String()}},
   112  	}
   113  
   114  	err := s.facade.FacadeCall(facadeMethod, args, &results)
   115  	if err != nil {
   116  		return nil, errors.Trace(err)
   117  	}
   118  	if len(results.Results) != 1 {
   119  		return nil, errors.Errorf("expected 1 result, got %d", len(results.Results))
   120  	}
   121  
   122  	r := results.Results[0]
   123  	if r.Error == nil {
   124  		tags := make([]names.UnitTag, len(r.Entities))
   125  		for i, e := range r.Entities {
   126  			tag, err := names.ParseUnitTag(e.Tag)
   127  			if err != nil {
   128  				return nil, errors.Trace(err)
   129  			}
   130  			tags[i] = tag
   131  		}
   132  		return tags, nil
   133  	}
   134  
   135  	if params.IsCodeNotFound(r.Error) {
   136  		return nil, errors.NewNotFound(r.Error, "")
   137  	}
   138  	return nil, errors.Trace(r.Error)
   139  }
   140  
   141  // SetMachineStatus sets the machine status in remote state.
   142  func (s *Client) SetMachineStatus(status model.UpgradeSeriesStatus, reason string) error {
   143  	var results params.ErrorResults
   144  	args := params.UpgradeSeriesStatusParams{
   145  		Params: []params.UpgradeSeriesStatusParam{{
   146  			Entity:  params.Entity{Tag: s.authTag.String()},
   147  			Status:  status,
   148  			Message: reason,
   149  		}},
   150  	}
   151  
   152  	err := s.facade.FacadeCall("SetMachineStatus", args, &results)
   153  	if err != nil {
   154  		return err
   155  	}
   156  	if len(results.Results) != 1 {
   157  		return errors.Errorf("expected 1 result, got %d", len(results.Results))
   158  	}
   159  
   160  	result := results.Results[0]
   161  	if result.Error != nil {
   162  		return result.Error
   163  	}
   164  	return nil
   165  }
   166  
   167  // StartUnitCompletion starts the complete phase for all subordinate units.
   168  func (s *Client) StartUnitCompletion(reason string) error {
   169  	var results params.ErrorResults
   170  	args := params.UpgradeSeriesStartUnitCompletionParam{
   171  		Entities: []params.Entity{{Tag: s.authTag.String()}},
   172  		Message:  reason,
   173  	}
   174  
   175  	err := s.facade.FacadeCall("StartUnitCompletion", args, &results)
   176  	if err != nil {
   177  		return err
   178  	}
   179  	if len(results.Results) != 1 {
   180  		return errors.Errorf("expected 1 result, got %d", len(results.Results))
   181  	}
   182  
   183  	result := results.Results[0]
   184  	if result.Error != nil {
   185  		return result.Error
   186  	}
   187  	return nil
   188  }
   189  
   190  // FinishUpgradeSeries notifies the controller that the upgrade process is
   191  // completely finished, passing the current host OS series.
   192  // We use the name "Finish" to distinguish this method from the various
   193  // "Complete" phases.
   194  func (s *Client) FinishUpgradeSeries(hostSeries string) error {
   195  	var results params.ErrorResults
   196  	args := params.UpdateSeriesArgs{Args: []params.UpdateSeriesArg{{
   197  		Entity: params.Entity{Tag: s.authTag.String()},
   198  		Series: hostSeries,
   199  	}}}
   200  
   201  	err := s.facade.FacadeCall("FinishUpgradeSeries", args, &results)
   202  	if err != nil {
   203  		return err
   204  	}
   205  	if len(results.Results) != 1 {
   206  		return errors.Errorf("expected 1 result, got %d", len(results.Results))
   207  	}
   208  
   209  	result := results.Results[0]
   210  	if result.Error != nil {
   211  		return result.Error
   212  	}
   213  	return nil
   214  }