200
215
c.Assert(cons, jc.DeepEquals, constraints.MustParse("mem=2G cpu-cores=2 networks=net1,net0,^net3,^net4"))
218
// TODO(wallyworld) - add another test that deploy with storage fails for older environments
219
// (need deploy client to be refactored to use API stub)
220
func (s *DeploySuite) TestStorage(c *gc.C) {
221
pm := poolmanager.New(state.NewStateSettings(s.State))
222
_, err := pm.Create("loop-pool", provider.LoopProviderType, map[string]interface{}{"foo": "bar"})
223
c.Assert(err, jc.ErrorIsNil)
225
testcharms.Repo.CharmArchivePath(s.SeriesPath, "storage-block")
226
err = runDeploy(c, "local:storage-block", "--storage", "data=loop-pool,1G")
227
c.Assert(err, jc.ErrorIsNil)
228
curl := charm.MustParseURL("local:trusty/storage-block-1")
229
service, _ := s.AssertService(c, "storage-block", curl, 1, 0)
231
cons, err := service.StorageConstraints()
232
c.Assert(err, jc.ErrorIsNil)
233
c.Assert(cons, jc.DeepEquals, map[string]state.StorageConstraints{
203
247
func (s *DeploySuite) TestSubordinateConstraints(c *gc.C) {
204
248
testcharms.Repo.CharmArchivePath(s.SeriesPath, "logging")
205
249
err := runDeploy(c, "local:logging", "--constraints", "mem=1G")
318
362
err := runDeploy(c, "--to", "0", "local:dummy", "portlandia")
319
363
c.Assert(err, gc.ErrorMatches, "machine 0 is the state server for a local environment and cannot host units")
366
// setupConfigFile creates a configuration file for testing set
367
// with the --config argument specifying a configuration file.
368
func setupConfigFile(c *gc.C, dir string) string {
369
ctx := coretesting.ContextForDir(c, dir)
370
path := ctx.AbsPath("testconfig.yaml")
371
content := []byte("dummy-service:\n skill-level: 9000\n username: admin001\n\n")
372
err := ioutil.WriteFile(path, content, 0666)
373
c.Assert(err, jc.ErrorIsNil)
377
type DeployCharmStoreSuite struct {
381
var _ = gc.Suite(&DeployCharmStoreSuite{})
383
var deployAuthorizationTests = []struct {
391
about: "public charm, success",
392
uploadURL: "cs:~bob/trusty/wordpress1-10",
393
deployURL: "cs:~bob/trusty/wordpress1",
394
expectOutput: `Added charm "cs:~bob/trusty/wordpress1-10" to the environment.`,
396
about: "public charm, fully resolved, success",
397
uploadURL: "cs:~bob/trusty/wordpress2-10",
398
deployURL: "cs:~bob/trusty/wordpress2-10",
399
expectOutput: `Added charm "cs:~bob/trusty/wordpress2-10" to the environment.`,
401
about: "non-public charm, success",
402
uploadURL: "cs:~bob/trusty/wordpress3-10",
403
deployURL: "cs:~bob/trusty/wordpress3",
404
readPermUser: clientUserName,
405
expectOutput: `Added charm "cs:~bob/trusty/wordpress3-10" to the environment.`,
407
about: "non-public charm, fully resolved, success",
408
uploadURL: "cs:~bob/trusty/wordpress4-10",
409
deployURL: "cs:~bob/trusty/wordpress4-10",
410
readPermUser: clientUserName,
411
expectOutput: `Added charm "cs:~bob/trusty/wordpress4-10" to the environment.`,
413
about: "non-public charm, access denied",
414
uploadURL: "cs:~bob/trusty/wordpress5-10",
415
deployURL: "cs:~bob/trusty/wordpress5",
417
expectError: `cannot resolve charm URL "cs:~bob/trusty/wordpress5": cannot get "/~bob/trusty/wordpress5/meta/any\?include=id": unauthorized: access denied for user "client-username"`,
419
about: "non-public charm, fully resolved, access denied",
420
uploadURL: "cs:~bob/trusty/wordpress6-47",
421
deployURL: "cs:~bob/trusty/wordpress6-47",
423
expectError: `cannot retrieve charm "cs:~bob/trusty/wordpress6-47": cannot get archive: unauthorized: access denied for user "client-username"`,
426
func (s *DeployCharmStoreSuite) TestDeployAuthorization(c *gc.C) {
427
for i, test := range deployAuthorizationTests {
428
c.Logf("test %d: %s", i, test.about)
429
url, _ := s.uploadCharm(c, test.uploadURL, "wordpress")
430
if test.readPermUser != "" {
431
s.changeReadPerm(c, url, test.readPermUser)
433
ctx, err := coretesting.RunCommand(c, envcmd.Wrap(&DeployCommand{}), test.deployURL, fmt.Sprintf("wordpress%d", i))
434
if test.expectError != "" {
435
c.Assert(err, gc.ErrorMatches, test.expectError)
438
c.Assert(err, jc.ErrorIsNil)
439
output := strings.Trim(coretesting.Stderr(ctx), "\n")
440
c.Assert(output, gc.Equals, test.expectOutput)
445
// clientUserCookie is the name of the cookie which is
446
// used to signal to the charmStoreSuite macaroon discharger
447
// that the client is a juju client rather than the juju environment.
448
clientUserCookie = "client"
450
// clientUserName is the name chosen for the juju client
451
// when it has authorized.
452
clientUserName = "client-username"
455
// charmStoreSuite is a suite fixture that puts the machinery in
456
// place to allow testing code that calls addCharmViaAPI.
457
type charmStoreSuite struct {
458
testing.JujuConnSuite
459
srv *charmstoretesting.Server
460
discharger *bakerytest.Discharger
463
func (s *charmStoreSuite) SetUpTest(c *gc.C) {
464
s.JujuConnSuite.SetUpTest(c)
466
// Set up the third party discharger.
467
s.discharger = bakerytest.NewDischarger(nil, func(req *http.Request, cond string, arg string) ([]checkers.Caveat, error) {
468
cookie, err := req.Cookie(clientUserCookie)
470
return nil, errors.New("discharge denied to non-clients")
472
return []checkers.Caveat{
473
checkers.DeclaredCaveat("username", cookie.Value),
477
// Set up the charm store testing server.
478
s.srv = charmstoretesting.OpenServer(c, s.Session, charmstore.ServerParams{
479
IdentityLocation: s.discharger.Location(),
480
PublicKeyLocator: s.discharger,
483
// Initialize the charm cache dir.
484
s.PatchValue(&charmrepo.CacheDir, c.MkDir())
486
// Point the CLI to the charm store testing server.
487
original := newCharmStoreClient
488
s.PatchValue(&newCharmStoreClient, func() (*csClient, error) {
489
csclient, err := original()
493
csclient.params.URL = s.srv.URL()
494
// Add a cookie so that the discharger can detect whether the
495
// HTTP client is the juju environment or the juju client.
496
lurl, err := url.Parse(s.discharger.Location())
500
csclient.params.HTTPClient.Jar.SetCookies(lurl, []*http.Cookie{{
501
Name: clientUserCookie,
502
Value: clientUserName,
507
// Point the Juju API server to the charm store testing server.
508
s.PatchValue(&csclient.ServerURL, s.srv.URL())
511
func (s *charmStoreSuite) TearDownTest(c *gc.C) {
514
s.JujuConnSuite.TearDownTest(c)
517
// uploadCharm adds a charm with the given URL and name to the charm store.
518
func (s *charmStoreSuite) uploadCharm(c *gc.C, url, name string) (*charm.URL, charm.Charm) {
519
id := charm.MustParseReference(url)
525
ch := testcharms.Repo.CharmArchive(c.MkDir(), name)
526
id = s.srv.UploadCharm(c, ch, id, promulgated)
527
return (*charm.URL)(id), ch
530
// changeReadPerm changes the read permission of the given charm URL.
531
// The charm must be present in the testing charm store.
532
func (s *charmStoreSuite) changeReadPerm(c *gc.C, url *charm.URL, perms ...string) {
533
err := s.srv.NewClient().Put("/"+url.Path()+"/meta/perm/read", perms)
534
c.Assert(err, jc.ErrorIsNil)