github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/cmd/juju/deploy_test.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package main
     5  
     6  import (
     7  	"strings"
     8  
     9  	"github.com/juju/cmd"
    10  	"github.com/juju/errors"
    11  	jc "github.com/juju/testing/checkers"
    12  	"github.com/juju/utils"
    13  	"github.com/juju/utils/featureflag"
    14  	gc "gopkg.in/check.v1"
    15  	"gopkg.in/juju/charm.v4"
    16  
    17  	"github.com/juju/juju/api"
    18  	"github.com/juju/juju/cmd/envcmd"
    19  	"github.com/juju/juju/constraints"
    20  	"github.com/juju/juju/environs/config"
    21  	"github.com/juju/juju/instance"
    22  	"github.com/juju/juju/juju/osenv"
    23  	"github.com/juju/juju/juju/testing"
    24  	"github.com/juju/juju/state"
    25  	"github.com/juju/juju/testcharms"
    26  	coretesting "github.com/juju/juju/testing"
    27  )
    28  
    29  type DeploySuite struct {
    30  	testing.RepoSuite
    31  }
    32  
    33  var _ = gc.Suite(&DeploySuite{})
    34  
    35  func runDeploy(c *gc.C, args ...string) error {
    36  	_, err := coretesting.RunCommand(c, envcmd.Wrap(&DeployCommand{}), args...)
    37  	return err
    38  }
    39  
    40  var initErrorTests = []struct {
    41  	args []string
    42  	err  string
    43  }{
    44  	{
    45  		args: nil,
    46  		err:  `no charm specified`,
    47  	}, {
    48  		args: []string{"charm-name", "service-name", "hotdog"},
    49  		err:  `unrecognized args: \["hotdog"\]`,
    50  	}, {
    51  		args: []string{"craz~ness"},
    52  		err:  `invalid charm name "craz~ness"`,
    53  	}, {
    54  		args: []string{"craziness", "burble-1"},
    55  		err:  `invalid service name "burble-1"`,
    56  	}, {
    57  		args: []string{"craziness", "burble1", "-n", "0"},
    58  		err:  `--num-units must be a positive integer`,
    59  	}, {
    60  		args: []string{"craziness", "burble1", "--to", "bigglesplop"},
    61  		err:  `invalid --to parameter "bigglesplop"`,
    62  	}, {
    63  		args: []string{"craziness", "burble1", "-n", "2", "--to", "123"},
    64  		err:  `cannot use --num-units > 1 with --to`,
    65  	}, {
    66  		args: []string{"craziness", "burble1", "--constraints", "gibber=plop"},
    67  		err:  `invalid value "gibber=plop" for flag --constraints: unknown constraint "gibber"`,
    68  	},
    69  }
    70  
    71  func (s *DeploySuite) TestInitErrors(c *gc.C) {
    72  	for i, t := range initErrorTests {
    73  		c.Logf("test %d", i)
    74  		err := coretesting.InitCommand(envcmd.Wrap(&DeployCommand{}), t.args)
    75  		c.Assert(err, gc.ErrorMatches, t.err)
    76  	}
    77  }
    78  
    79  func (s *DeploySuite) TestNoCharm(c *gc.C) {
    80  	err := runDeploy(c, "local:unknown-123")
    81  	c.Assert(err, gc.ErrorMatches, `charm not found in ".*": local:trusty/unknown-123`)
    82  }
    83  
    84  func (s *DeploySuite) TestBlockDeploy(c *gc.C) {
    85  	// Block operation
    86  	s.AssertConfigParameterUpdated(c, "block-all-changes", true)
    87  	testcharms.Repo.CharmArchivePath(s.SeriesPath, "dummy")
    88  	err := runDeploy(c, "local:dummy", "some-service-name")
    89  	c.Assert(err, gc.ErrorMatches, cmd.ErrSilent.Error())
    90  
    91  	// msg is logged
    92  	stripped := strings.Replace(c.GetTestLog(), "\n", "", -1)
    93  	c.Check(stripped, gc.Matches, ".*To unblock changes.*")
    94  }
    95  
    96  func (s *DeploySuite) TestCharmDir(c *gc.C) {
    97  	testcharms.Repo.ClonedDirPath(s.SeriesPath, "dummy")
    98  	err := runDeploy(c, "local:dummy")
    99  	c.Assert(err, jc.ErrorIsNil)
   100  	curl := charm.MustParseURL("local:trusty/dummy-1")
   101  	s.AssertService(c, "dummy", curl, 1, 0)
   102  }
   103  
   104  func (s *DeploySuite) TestUpgradeReportsDeprecated(c *gc.C) {
   105  	testcharms.Repo.ClonedDirPath(s.SeriesPath, "dummy")
   106  	ctx, err := coretesting.RunCommand(c, envcmd.Wrap(&DeployCommand{}), "local:dummy", "-u")
   107  	c.Assert(err, jc.ErrorIsNil)
   108  
   109  	c.Assert(coretesting.Stdout(ctx), gc.Equals, "")
   110  	output := strings.Split(coretesting.Stderr(ctx), "\n")
   111  	c.Check(output[0], gc.Matches, `Added charm ".*" to the environment.`)
   112  	c.Check(output[1], gc.Equals, "--upgrade (or -u) is deprecated and ignored; charms are always deployed with a unique revision.")
   113  }
   114  
   115  func (s *DeploySuite) TestUpgradeCharmDir(c *gc.C) {
   116  	// Add the charm, so the url will exist and a new revision will be
   117  	// picked in ServiceDeploy.
   118  	dummyCharm := s.AddTestingCharm(c, "dummy")
   119  
   120  	dirPath := testcharms.Repo.ClonedDirPath(s.SeriesPath, "dummy")
   121  	err := runDeploy(c, "local:quantal/dummy")
   122  	c.Assert(err, jc.ErrorIsNil)
   123  	upgradedRev := dummyCharm.Revision() + 1
   124  	curl := dummyCharm.URL().WithRevision(upgradedRev)
   125  	s.AssertService(c, "dummy", curl, 1, 0)
   126  	// Check the charm dir was left untouched.
   127  	ch, err := charm.ReadCharmDir(dirPath)
   128  	c.Assert(err, jc.ErrorIsNil)
   129  	c.Assert(ch.Revision(), gc.Equals, 1)
   130  }
   131  
   132  func (s *DeploySuite) TestCharmBundle(c *gc.C) {
   133  	testcharms.Repo.CharmArchivePath(s.SeriesPath, "dummy")
   134  	err := runDeploy(c, "local:dummy", "some-service-name")
   135  	c.Assert(err, jc.ErrorIsNil)
   136  	curl := charm.MustParseURL("local:trusty/dummy-1")
   137  	s.AssertService(c, "some-service-name", curl, 1, 0)
   138  }
   139  
   140  func (s *DeploySuite) TestSubordinateCharm(c *gc.C) {
   141  	testcharms.Repo.CharmArchivePath(s.SeriesPath, "logging")
   142  	err := runDeploy(c, "local:logging")
   143  	c.Assert(err, jc.ErrorIsNil)
   144  	curl := charm.MustParseURL("local:trusty/logging-1")
   145  	s.AssertService(c, "logging", curl, 0, 0)
   146  }
   147  
   148  func (s *DeploySuite) TestConfig(c *gc.C) {
   149  	testcharms.Repo.CharmArchivePath(s.SeriesPath, "dummy")
   150  	path := setupConfigFile(c, c.MkDir())
   151  	err := runDeploy(c, "local:dummy", "dummy-service", "--config", path)
   152  	c.Assert(err, jc.ErrorIsNil)
   153  	service, err := s.State.Service("dummy-service")
   154  	c.Assert(err, jc.ErrorIsNil)
   155  	settings, err := service.ConfigSettings()
   156  	c.Assert(err, jc.ErrorIsNil)
   157  	c.Assert(settings, gc.DeepEquals, charm.Settings{
   158  		"skill-level": int64(9000),
   159  		"username":    "admin001",
   160  	})
   161  }
   162  
   163  func (s *DeploySuite) TestRelativeConfigPath(c *gc.C) {
   164  	testcharms.Repo.CharmArchivePath(s.SeriesPath, "dummy")
   165  	// Putting a config file in home is okay as $HOME is set to a tempdir
   166  	setupConfigFile(c, utils.Home())
   167  	err := runDeploy(c, "local:dummy", "dummy-service", "--config", "~/testconfig.yaml")
   168  	c.Assert(err, jc.ErrorIsNil)
   169  }
   170  
   171  func (s *DeploySuite) TestConfigError(c *gc.C) {
   172  	testcharms.Repo.CharmArchivePath(s.SeriesPath, "dummy")
   173  	path := setupConfigFile(c, c.MkDir())
   174  	err := runDeploy(c, "local:dummy", "other-service", "--config", path)
   175  	c.Assert(err, gc.ErrorMatches, `no settings found for "other-service"`)
   176  	_, err = s.State.Service("other-service")
   177  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   178  }
   179  
   180  func (s *DeploySuite) TestConstraints(c *gc.C) {
   181  	testcharms.Repo.CharmArchivePath(s.SeriesPath, "dummy")
   182  	err := runDeploy(c, "local:dummy", "--constraints", "mem=2G cpu-cores=2 networks=net1,^net2")
   183  	c.Assert(err, jc.ErrorIsNil)
   184  	curl := charm.MustParseURL("local:trusty/dummy-1")
   185  	service, _ := s.AssertService(c, "dummy", curl, 1, 0)
   186  	cons, err := service.Constraints()
   187  	c.Assert(err, jc.ErrorIsNil)
   188  	c.Assert(cons, jc.DeepEquals, constraints.MustParse("mem=2G cpu-cores=2 networks=net1,^net2"))
   189  }
   190  
   191  func (s *DeploySuite) TestNetworks(c *gc.C) {
   192  	testcharms.Repo.CharmArchivePath(s.SeriesPath, "dummy")
   193  	err := runDeploy(c, "local:dummy", "--networks", ", net1, net2 , ", "--constraints", "mem=2G cpu-cores=2 networks=net1,net0,^net3,^net4")
   194  	c.Assert(err, jc.ErrorIsNil)
   195  	curl := charm.MustParseURL("local:trusty/dummy-1")
   196  	service, _ := s.AssertService(c, "dummy", curl, 1, 0)
   197  	networks, err := service.Networks()
   198  	c.Assert(err, jc.ErrorIsNil)
   199  	c.Assert(networks, jc.DeepEquals, []string{"net1", "net2"})
   200  	cons, err := service.Constraints()
   201  	c.Assert(err, jc.ErrorIsNil)
   202  	c.Assert(cons, jc.DeepEquals, constraints.MustParse("mem=2G cpu-cores=2 networks=net1,net0,^net3,^net4"))
   203  }
   204  
   205  func (s *DeploySuite) TestStorageWithoutFeatureFlag(c *gc.C) {
   206  	err := runDeploy(c, "local:storage-block", "--storage", "data=1G")
   207  	c.Assert(err, gc.ErrorMatches, "flag provided but not defined: --storage")
   208  }
   209  
   210  func (s *DeploySuite) TestStorage(c *gc.C) {
   211  	s.PatchEnvironment(osenv.JujuFeatureFlagEnvKey, "storage")
   212  	featureflag.SetFlagsFromEnvironment(osenv.JujuFeatureFlagEnvKey)
   213  
   214  	testcharms.Repo.CharmArchivePath(s.SeriesPath, "storage-block")
   215  	err := runDeploy(c, "local:storage-block", "--storage", "data=1G")
   216  	c.Assert(err, jc.ErrorIsNil)
   217  	curl := charm.MustParseURL("local:trusty/storage-block-1")
   218  	service, _ := s.AssertService(c, "storage-block", curl, 1, 0)
   219  
   220  	cons, err := service.StorageConstraints()
   221  	c.Assert(err, jc.ErrorIsNil)
   222  	c.Assert(cons, jc.DeepEquals, map[string]state.StorageConstraints{
   223  		"data": {
   224  			Count: 1,
   225  			Size:  1024,
   226  		},
   227  	})
   228  }
   229  
   230  func (s *DeploySuite) TestSubordinateConstraints(c *gc.C) {
   231  	testcharms.Repo.CharmArchivePath(s.SeriesPath, "logging")
   232  	err := runDeploy(c, "local:logging", "--constraints", "mem=1G")
   233  	c.Assert(err, gc.ErrorMatches, "cannot use --constraints with subordinate service")
   234  }
   235  
   236  func (s *DeploySuite) TestNumUnits(c *gc.C) {
   237  	testcharms.Repo.CharmArchivePath(s.SeriesPath, "dummy")
   238  	err := runDeploy(c, "local:dummy", "-n", "13")
   239  	c.Assert(err, jc.ErrorIsNil)
   240  	curl := charm.MustParseURL("local:trusty/dummy-1")
   241  	s.AssertService(c, "dummy", curl, 13, 0)
   242  }
   243  
   244  func (s *DeploySuite) TestNumUnitsSubordinate(c *gc.C) {
   245  	testcharms.Repo.CharmArchivePath(s.SeriesPath, "logging")
   246  	err := runDeploy(c, "--num-units", "3", "local:logging")
   247  	c.Assert(err, gc.ErrorMatches, "cannot use --num-units or --to with subordinate service")
   248  	_, err = s.State.Service("dummy")
   249  	c.Assert(err, gc.ErrorMatches, `service "dummy" not found`)
   250  }
   251  
   252  func (s *DeploySuite) assertForceMachine(c *gc.C, machineId string) {
   253  	svc, err := s.State.Service("portlandia")
   254  	c.Assert(err, jc.ErrorIsNil)
   255  	units, err := svc.AllUnits()
   256  	c.Assert(err, jc.ErrorIsNil)
   257  	c.Assert(units, gc.HasLen, 1)
   258  	mid, err := units[0].AssignedMachineId()
   259  	c.Assert(err, jc.ErrorIsNil)
   260  	c.Assert(mid, gc.Equals, machineId)
   261  }
   262  
   263  func (s *DeploySuite) TestForceMachine(c *gc.C) {
   264  	testcharms.Repo.CharmArchivePath(s.SeriesPath, "dummy")
   265  	machine, err := s.State.AddMachine(coretesting.FakeDefaultSeries, state.JobHostUnits)
   266  	c.Assert(err, jc.ErrorIsNil)
   267  	err = runDeploy(c, "--to", machine.Id(), "local:dummy", "portlandia")
   268  	c.Assert(err, jc.ErrorIsNil)
   269  	s.assertForceMachine(c, machine.Id())
   270  }
   271  
   272  func (s *DeploySuite) TestForceMachineExistingContainer(c *gc.C) {
   273  	testcharms.Repo.CharmArchivePath(s.SeriesPath, "dummy")
   274  	template := state.MachineTemplate{
   275  		Series: coretesting.FakeDefaultSeries,
   276  		Jobs:   []state.MachineJob{state.JobHostUnits},
   277  	}
   278  	container, err := s.State.AddMachineInsideNewMachine(template, template, instance.LXC)
   279  	c.Assert(err, jc.ErrorIsNil)
   280  	err = runDeploy(c, "--to", container.Id(), "local:dummy", "portlandia")
   281  	c.Assert(err, jc.ErrorIsNil)
   282  	s.assertForceMachine(c, container.Id())
   283  	machines, err := s.State.AllMachines()
   284  	c.Assert(err, jc.ErrorIsNil)
   285  	c.Assert(machines, gc.HasLen, 2)
   286  }
   287  
   288  func (s *DeploySuite) TestForceMachineNewContainer(c *gc.C) {
   289  	testcharms.Repo.CharmArchivePath(s.SeriesPath, "dummy")
   290  	machine, err := s.State.AddMachine(coretesting.FakeDefaultSeries, state.JobHostUnits)
   291  	c.Assert(err, jc.ErrorIsNil)
   292  	err = runDeploy(c, "--to", "lxc:"+machine.Id(), "local:dummy", "portlandia")
   293  	c.Assert(err, jc.ErrorIsNil)
   294  	s.assertForceMachine(c, machine.Id()+"/lxc/0")
   295  	machines, err := s.State.AllMachines()
   296  	c.Assert(err, jc.ErrorIsNil)
   297  	c.Assert(machines, gc.HasLen, 2)
   298  }
   299  
   300  func (s *DeploySuite) TestForceMachineNotFound(c *gc.C) {
   301  	testcharms.Repo.CharmArchivePath(s.SeriesPath, "dummy")
   302  	err := runDeploy(c, "--to", "42", "local:dummy", "portlandia")
   303  	c.Assert(err, gc.ErrorMatches, `cannot deploy "portlandia" to machine 42: machine 42 not found`)
   304  	_, err = s.State.Service("portlandia")
   305  	c.Assert(err, gc.ErrorMatches, `service "portlandia" not found`)
   306  }
   307  
   308  func (s *DeploySuite) TestForceMachineSubordinate(c *gc.C) {
   309  	machine, err := s.State.AddMachine(coretesting.FakeDefaultSeries, state.JobHostUnits)
   310  	c.Assert(err, jc.ErrorIsNil)
   311  	testcharms.Repo.CharmArchivePath(s.SeriesPath, "logging")
   312  	err = runDeploy(c, "--to", machine.Id(), "local:logging")
   313  	c.Assert(err, gc.ErrorMatches, "cannot use --num-units or --to with subordinate service")
   314  	_, err = s.State.Service("dummy")
   315  	c.Assert(err, gc.ErrorMatches, `service "dummy" not found`)
   316  }
   317  
   318  func (s *DeploySuite) TestNonLocalCannotHostUnits(c *gc.C) {
   319  	err := runDeploy(c, "--to", "0", "local:dummy", "portlandia")
   320  	c.Assert(err, gc.Not(gc.ErrorMatches), "machine 0 is the state server for a local environment and cannot host units")
   321  }
   322  
   323  type DeployLocalSuite struct {
   324  	testing.RepoSuite
   325  }
   326  
   327  var _ = gc.Suite(&DeployLocalSuite{})
   328  
   329  func (s *DeployLocalSuite) SetUpTest(c *gc.C) {
   330  	s.RepoSuite.SetUpTest(c)
   331  
   332  	// override provider type
   333  	s.PatchValue(&getClientConfig, func(client *api.Client) (*config.Config, error) {
   334  		attrs, err := client.EnvironmentGet()
   335  		if err != nil {
   336  			return nil, err
   337  		}
   338  		attrs["type"] = "local"
   339  
   340  		return config.New(config.NoDefaults, attrs)
   341  	})
   342  }
   343  
   344  func (s *DeployLocalSuite) TestLocalCannotHostUnits(c *gc.C) {
   345  	err := runDeploy(c, "--to", "0", "local:dummy", "portlandia")
   346  	c.Assert(err, gc.ErrorMatches, "machine 0 is the state server for a local environment and cannot host units")
   347  }