~juju-qa/ubuntu/xenial/juju/xenial-2.0-beta3

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/api/client.go

  • Committer: Martin Packman
  • Date: 2016-03-30 19:31:08 UTC
  • mfrom: (1.1.41)
  • Revision ID: martin.packman@canonical.com-20160330193108-h9iz3ak334uk0z5r
Merge new upstream source 2.0~beta3

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
        "github.com/juju/errors"
17
17
        "github.com/juju/loggo"
18
18
        "github.com/juju/names"
 
19
        "github.com/juju/version"
19
20
        "golang.org/x/net/websocket"
20
21
        "gopkg.in/juju/charm.v6-unstable"
21
22
        "gopkg.in/macaroon.v1"
25
26
        "github.com/juju/juju/constraints"
26
27
        "github.com/juju/juju/network"
27
28
        "github.com/juju/juju/tools"
28
 
        "github.com/juju/juju/version"
29
29
)
30
30
 
31
31
// Client represents the client-accessible part of the state.
45
45
        return &result, nil
46
46
}
47
47
 
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
 
50
// for <name> unit
 
51
func (c *Client) StatusHistory(kind params.HistoryKind, name string, size int) (*params.StatusHistoryResults, error) {
 
52
        var results params.StatusHistoryResults
 
53
        args := params.StatusHistoryArgs{
53
54
                Kind: kind,
54
55
                Size: size,
55
 
                Name: unitName,
 
56
                Name: name,
56
57
        }
57
 
        err := c.facade.FacadeCall("UnitStatusHistory", args, &results)
 
58
        err := c.facade.FacadeCall("StatusHistory", args, &results)
58
59
        if err != nil {
59
 
                return &params.UnitStatusHistory{}, errors.Trace(err)
 
60
                return &params.StatusHistoryResults{}, errors.Trace(err)
60
61
        }
61
62
        return &results, nil
62
63
}
63
64
 
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 {
69
 
                return nil, err
70
 
        }
71
 
        return &result, nil
72
 
}
73
 
 
74
65
// Resolved clears errors on a unit.
75
66
func (c *Client) Resolved(unit string, retry bool) error {
76
67
        p := params.Resolved{
194
185
        return tag.Id()
195
186
}
196
187
 
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 {
201
 
                if &user != nil {
202
 
                        args.Changes = append(args.Changes, params.ModifyModelUser{
203
 
                                UserTag: user.String(),
204
 
                                Action:  params.AddModelUser,
205
 
                        })
206
 
                }
207
 
        }
208
 
 
209
 
        var result params.ErrorResults
210
 
        err := c.facade.FacadeCall("ShareModel", args, &result)
211
 
        if err != nil {
212
 
                return errors.Trace(err)
213
 
        }
214
 
 
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
219
 
                }
220
 
        }
221
 
        return result.Combine()
222
 
}
223
 
 
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
239
203
        return info, nil
240
204
}
241
205
 
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 {
246
 
                if &user != nil {
247
 
                        args.Changes = append(args.Changes, params.ModifyModelUser{
248
 
                                UserTag: user.String(),
249
 
                                Action:  params.RemoveModelUser,
250
 
                        })
251
 
                }
252
 
        }
253
 
 
254
 
        var result params.ErrorResults
255
 
        err := c.facade.FacadeCall("ShareModel", args, &result)
256
 
        if err != nil {
257
 
                return errors.Trace(err)
258
 
        }
259
 
 
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
264
 
                }
265
 
        }
266
 
        return result.Combine()
267
 
}
268
 
 
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())
367
304
        }
368
 
        httpClient, err := c.st.HTTPClient()
369
 
        if err != nil {
 
305
 
 
306
        if err := c.validateCharmVersion(ch); err != nil {
370
307
                return nil, errors.Trace(err)
371
308
        }
 
309
 
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)
396
334
        }
397
335
 
398
 
        req, err := http.NewRequest("POST", "/charms?series="+curl.Series, nil)
 
336
        curl, err := c.UploadCharm(curl, archive)
399
337
        if err != nil {
400
 
                return nil, errors.Annotate(err, "cannot create upload request")
 
338
                return nil, errors.Trace(err)
401
339
        }
402
 
        req.Header.Set("Content-Type", "application/zip")
 
340
        return curl, nil
 
341
}
403
342
 
 
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)
407
350
        }
408
 
        curl, err = charm.ParseURL(resp.CharmURL)
 
351
 
 
352
        curl, err := charm.ParseURL(resp.CharmURL)
409
353
        if err != nil {
410
354
                return nil, errors.Annotatef(err, "bad charm URL in response")
411
355
        }
412
356
        return curl, nil
413
357
}
414
358
 
 
359
type minJujuVersionErr struct {
 
360
        *errors.Err
 
361
}
 
362
 
 
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)",
 
365
                minver, jujuver)
 
366
        err.SetLocation(1)
 
367
        return minJujuVersionErr{&err}
 
368
}
 
369
 
 
370
func (c *Client) validateCharmVersion(ch charm.Charm) error {
 
371
        minver := ch.Meta().MinJujuVersion
 
372
        if minver != version.Zero {
 
373
                agentver, err := c.AgentVersion()
 
374
                if err != nil {
 
375
                        return errors.Trace(err)
 
376
                }
 
377
 
 
378
                if minver.Compare(agentver) > 0 {
 
379
                        return minVersionError(minver, agentver)
 
380
                }
 
381
        }
 
382
        return nil
 
383
}
 
384
 
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, ","))
468
 
 
469
 
        req, err := http.NewRequest("POST", endpoint, nil)
470
 
        if err != nil {
471
 
                return nil, errors.Annotate(err, "cannot create upload request")
472
 
        }
473
 
        req.Header.Set("Content-Type", "application/x-tar-gz")
474
 
 
475
 
        httpClient, err := c.st.HTTPClient()
476
 
        if err != nil {
477
 
                return nil, errors.Trace(err)
478
 
        }
 
438
        contentType := "application/x-tar-gz"
479
439
        var resp params.ToolsResult
480
 
        err = httpClient.Do(req, r, &resp)
481
 
        if err != nil {
482
 
                msg := err.Error()
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
487
 
                        err = &params.Error{
488
 
                                Code:    params.CodeOperationBlocked,
489
 
                                Message: msg,
490
 
                        }
491
 
                }
 
440
        if err := c.httpPost(r, endpoint, contentType, &resp); err != nil {
492
441
                return nil, errors.Trace(err)
493
442
        }
494
443
        return resp.Tools, nil
495
444
}
496
445
 
 
446
func (c *Client) httpPost(content io.ReadSeeker, endpoint, contentType string, response interface{}) error {
 
447
        req, err := http.NewRequest("POST", endpoint, nil)
 
448
        if err != nil {
 
449
                return errors.Annotate(err, "cannot create upload request")
 
450
        }
 
451
        req.Header.Set("Content-Type", contentType)
 
452
 
 
453
        // The returned httpClient sets the base url to /model/<uuid> if it can.
 
454
        httpClient, err := c.st.HTTPClient()
 
455
        if err != nil {
 
456
                return errors.Trace(err)
 
457
        }
 
458
 
 
459
        if err := httpClient.Do(req, content, response); err != nil {
 
460
                return errors.Trace(err)
 
461
        }
 
462
        return nil
 
463
}
 
464
 
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