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 }