45
45
return &result, nil
48
// UnitStatusHistory retrieves the last <size> results of <kind:combined|agent|workload> status
49
// for <unitName> unit
50
func (c *Client) UnitStatusHistory(kind params.HistoryKind, unitName string, size int) (*params.UnitStatusHistory, error) {
51
var results params.UnitStatusHistory
52
args := params.StatusHistory{
48
// StatusHistory retrieves the last <size> results of
49
// <kind:combined|agent|workload|machine|machineinstance|container|containerinstance> status
51
func (c *Client) StatusHistory(kind params.HistoryKind, name string, size int) (*params.StatusHistoryResults, error) {
52
var results params.StatusHistoryResults
53
args := params.StatusHistoryArgs{
57
err := c.facade.FacadeCall("UnitStatusHistory", args, &results)
58
err := c.facade.FacadeCall("StatusHistory", args, &results)
59
return ¶ms.UnitStatusHistory{}, errors.Trace(err)
60
return ¶ms.StatusHistoryResults{}, errors.Trace(err)
61
62
return &results, nil
64
// LegacyStatus is a stub version of Status that 1.16 introduced. Should be
65
// removed along with structs when api versioning makes it safe to do so.
66
func (c *Client) LegacyStatus() (*params.LegacyStatus, error) {
67
var result params.LegacyStatus
68
if err := c.facade.FacadeCall("Status", nil, &result); err != nil {
74
65
// Resolved clears errors on a unit.
75
66
func (c *Client) Resolved(unit string, retry bool) error {
76
67
p := params.Resolved{
197
// ShareModel allows the given users access to the model.
198
func (c *Client) ShareModel(users ...names.UserTag) error {
199
var args params.ModifyModelUsers
200
for _, user := range users {
202
args.Changes = append(args.Changes, params.ModifyModelUser{
203
UserTag: user.String(),
204
Action: params.AddModelUser,
209
var result params.ErrorResults
210
err := c.facade.FacadeCall("ShareModel", args, &result)
212
return errors.Trace(err)
215
for i, r := range result.Results {
216
if r.Error != nil && r.Error.Code == params.CodeAlreadyExists {
217
logger.Warningf("model is already shared with %s", users[i].Canonical())
218
result.Results[i].Error = nil
221
return result.Combine()
224
188
// ModelUserInfo returns information on all users in the model.
225
189
func (c *Client) ModelUserInfo() ([]params.ModelUserInfo, error) {
226
190
var results params.ModelUserInfoResults
242
// UnshareModel removes access to the model for the given users.
243
func (c *Client) UnshareModel(users ...names.UserTag) error {
244
var args params.ModifyModelUsers
245
for _, user := range users {
247
args.Changes = append(args.Changes, params.ModifyModelUser{
248
UserTag: user.String(),
249
Action: params.RemoveModelUser,
254
var result params.ErrorResults
255
err := c.facade.FacadeCall("ShareModel", args, &result)
257
return errors.Trace(err)
260
for i, r := range result.Results {
261
if r.Error != nil && r.Error.Code == params.CodeNotFound {
262
logger.Warningf("model was not previously shared with user %s", users[i].Canonical())
263
result.Results[i].Error = nil
266
return result.Combine()
269
206
// WatchAll holds the id of the newly-created AllWatcher/AllModelWatcher.
270
207
type WatchAll struct {
271
208
AllWatcherId string
365
302
if curl.Schema != "local" {
366
303
return nil, errors.Errorf("expected charm URL with local: schema, got %q", curl.String())
368
httpClient, err := c.st.HTTPClient()
306
if err := c.validateCharmVersion(ch); err != nil {
370
307
return nil, errors.Trace(err)
372
310
// Package the charm for uploading.
373
311
var archive *os.File
374
312
switch ch := ch.(type) {
395
333
return nil, errors.Errorf("unknown charm type %T", ch)
398
req, err := http.NewRequest("POST", "/charms?series="+curl.Series, nil)
336
curl, err := c.UploadCharm(curl, archive)
400
return nil, errors.Annotate(err, "cannot create upload request")
338
return nil, errors.Trace(err)
402
req.Header.Set("Content-Type", "application/zip")
343
// UploadCharm sends the content to the API server using an HTTP post.
344
func (c *Client) UploadCharm(curl *charm.URL, content io.ReadSeeker) (*charm.URL, error) {
345
endpoint := "/charms?series=" + curl.Series
346
contentType := "application/zip"
404
347
var resp params.CharmsResponse
405
if err := httpClient.Do(req, archive, &resp); err != nil {
348
if err := c.httpPost(content, endpoint, contentType, &resp); err != nil {
406
349
return nil, errors.Trace(err)
408
curl, err = charm.ParseURL(resp.CharmURL)
352
curl, err := charm.ParseURL(resp.CharmURL)
410
354
return nil, errors.Annotatef(err, "bad charm URL in response")
359
type minJujuVersionErr struct {
363
func minVersionError(minver, jujuver version.Number) error {
364
err := errors.NewErr("charm's min version (%s) is higher than this juju environment's version (%s)",
367
return minJujuVersionErr{&err}
370
func (c *Client) validateCharmVersion(ch charm.Charm) error {
371
minver := ch.Meta().MinJujuVersion
372
if minver != version.Zero {
373
agentver, err := c.AgentVersion()
375
return errors.Trace(err)
378
if minver.Compare(agentver) > 0 {
379
return minVersionError(minver, agentver)
415
385
// AddCharm adds the given charm URL (which must include revision) to
416
386
// the model, if it does not exist yet. Local charms are not
417
387
// supported, only charm store URLs. See also AddLocalCharm() in the
465
435
// UploadTools uploads tools at the specified location to the API server over HTTPS.
466
436
func (c *Client) UploadTools(r io.ReadSeeker, vers version.Binary, additionalSeries ...string) (*tools.Tools, error) {
467
437
endpoint := fmt.Sprintf("/tools?binaryVersion=%s&series=%s", vers, strings.Join(additionalSeries, ","))
469
req, err := http.NewRequest("POST", endpoint, nil)
471
return nil, errors.Annotate(err, "cannot create upload request")
473
req.Header.Set("Content-Type", "application/x-tar-gz")
475
httpClient, err := c.st.HTTPClient()
477
return nil, errors.Trace(err)
438
contentType := "application/x-tar-gz"
479
439
var resp params.ToolsResult
480
err = httpClient.Do(req, r, &resp)
483
if params.ErrCode(err) == "" && strings.Contains(msg, params.CodeOperationBlocked) {
484
// We're probably talking to an old version of the API server
485
// that doesn't provide error codes.
486
// See https://bugs.launchpad.net/juju-core/+bug/1499277
488
Code: params.CodeOperationBlocked,
440
if err := c.httpPost(r, endpoint, contentType, &resp); err != nil {
492
441
return nil, errors.Trace(err)
494
443
return resp.Tools, nil
446
func (c *Client) httpPost(content io.ReadSeeker, endpoint, contentType string, response interface{}) error {
447
req, err := http.NewRequest("POST", endpoint, nil)
449
return errors.Annotate(err, "cannot create upload request")
451
req.Header.Set("Content-Type", contentType)
453
// The returned httpClient sets the base url to /model/<uuid> if it can.
454
httpClient, err := c.st.HTTPClient()
456
return errors.Trace(err)
459
if err := httpClient.Do(req, content, response); err != nil {
460
return errors.Trace(err)
497
465
// APIHostPorts returns a slice of network.HostPort for each API server.
498
466
func (c *Client) APIHostPorts() ([][]network.HostPort, error) {
499
467
var result params.APIHostPortsResult