github.com/mattyw/juju@v0.0.0-20140610034352-732aecd63861/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/errors"
    10  	jc "github.com/juju/testing/checkers"
    11  	"github.com/juju/utils"
    12  	gc "launchpad.net/gocheck"
    13  
    14  	"github.com/juju/juju/charm"
    15  	charmtesting "github.com/juju/juju/charm/testing"
    16  	"github.com/juju/juju/cmd/envcmd"
    17  	"github.com/juju/juju/constraints"
    18  	"github.com/juju/juju/instance"
    19  	"github.com/juju/juju/juju/testing"
    20  	"github.com/juju/juju/state"
    21  	coretesting "github.com/juju/juju/testing"
    22  )
    23  
    24  type DeploySuite struct {
    25  	testing.RepoSuite
    26  }
    27  
    28  var _ = gc.Suite(&DeploySuite{})
    29  
    30  func runDeploy(c *gc.C, args ...string) error {
    31  	_, err := coretesting.RunCommand(c, envcmd.Wrap(&DeployCommand{}), args...)
    32  	return err
    33  }
    34  
    35  var initErrorTests = []struct {
    36  	args []string
    37  	err  string
    38  }{
    39  	{
    40  		args: nil,
    41  		err:  `no charm specified`,
    42  	}, {
    43  		args: []string{"charm-name", "service-name", "hotdog"},
    44  		err:  `unrecognized args: \["hotdog"\]`,
    45  	}, {
    46  		args: []string{"craz~ness"},
    47  		err:  `invalid charm name "craz~ness"`,
    48  	}, {
    49  		args: []string{"craziness", "burble-1"},
    50  		err:  `invalid service name "burble-1"`,
    51  	}, {
    52  		args: []string{"craziness", "burble1", "-n", "0"},
    53  		err:  `--num-units must be a positive integer`,
    54  	}, {
    55  		args: []string{"craziness", "burble1", "--to", "bigglesplop"},
    56  		err:  `invalid --to parameter "bigglesplop"`,
    57  	}, {
    58  		args: []string{"craziness", "burble1", "-n", "2", "--to", "123"},
    59  		err:  `cannot use --num-units > 1 with --to`,
    60  	}, {
    61  		args: []string{"craziness", "burble1", "--constraints", "gibber=plop"},
    62  		err:  `invalid value "gibber=plop" for flag --constraints: unknown constraint "gibber"`,
    63  	},
    64  }
    65  
    66  func (s *DeploySuite) TestInitErrors(c *gc.C) {
    67  	for i, t := range initErrorTests {
    68  		c.Logf("test %d", i)
    69  		err := coretesting.InitCommand(envcmd.Wrap(&DeployCommand{}), t.args)
    70  		c.Assert(err, gc.ErrorMatches, t.err)
    71  	}
    72  }
    73  
    74  func (s *DeploySuite) TestNoCharm(c *gc.C) {
    75  	err := runDeploy(c, "local:unknown-123")
    76  	c.Assert(err, gc.ErrorMatches, `charm not found in ".*": local:precise/unknown-123`)
    77  }
    78  
    79  func (s *DeploySuite) TestCharmDir(c *gc.C) {
    80  	charmtesting.Charms.ClonedDirPath(s.SeriesPath, "dummy")
    81  	err := runDeploy(c, "local:dummy")
    82  	c.Assert(err, gc.IsNil)
    83  	curl := charm.MustParseURL("local:precise/dummy-1")
    84  	s.AssertService(c, "dummy", curl, 1, 0)
    85  }
    86  
    87  func (s *DeploySuite) TestUpgradeReportsDeprecated(c *gc.C) {
    88  	charmtesting.Charms.ClonedDirPath(s.SeriesPath, "dummy")
    89  	ctx, err := coretesting.RunCommand(c, envcmd.Wrap(&DeployCommand{}), "local:dummy", "-u")
    90  	c.Assert(err, gc.IsNil)
    91  
    92  	c.Assert(coretesting.Stdout(ctx), gc.Equals, "")
    93  	output := strings.Split(coretesting.Stderr(ctx), "\n")
    94  	c.Check(output[0], gc.Matches, `Added charm ".*" to the environment.`)
    95  	c.Check(output[1], gc.Equals, "--upgrade (or -u) is deprecated and ignored; charms are always deployed with a unique revision.")
    96  }
    97  
    98  func (s *DeploySuite) TestUpgradeCharmDir(c *gc.C) {
    99  	// Add the charm, so the url will exist and a new revision will be
   100  	// picked in ServiceDeploy.
   101  	dummyCharm := s.AddTestingCharm(c, "dummy")
   102  
   103  	dirPath := charmtesting.Charms.ClonedDirPath(s.SeriesPath, "dummy")
   104  	err := runDeploy(c, "local:quantal/dummy")
   105  	c.Assert(err, gc.IsNil)
   106  	upgradedRev := dummyCharm.Revision() + 1
   107  	curl := dummyCharm.URL().WithRevision(upgradedRev)
   108  	s.AssertService(c, "dummy", curl, 1, 0)
   109  	// Check the charm dir was left untouched.
   110  	ch, err := charm.ReadDir(dirPath)
   111  	c.Assert(err, gc.IsNil)
   112  	c.Assert(ch.Revision(), gc.Equals, 1)
   113  }
   114  
   115  func (s *DeploySuite) TestCharmBundle(c *gc.C) {
   116  	charmtesting.Charms.BundlePath(s.SeriesPath, "dummy")
   117  	err := runDeploy(c, "local:dummy", "some-service-name")
   118  	c.Assert(err, gc.IsNil)
   119  	curl := charm.MustParseURL("local:precise/dummy-1")
   120  	s.AssertService(c, "some-service-name", curl, 1, 0)
   121  }
   122  
   123  func (s *DeploySuite) TestSubordinateCharm(c *gc.C) {
   124  	charmtesting.Charms.BundlePath(s.SeriesPath, "logging")
   125  	err := runDeploy(c, "local:logging")
   126  	c.Assert(err, gc.IsNil)
   127  	curl := charm.MustParseURL("local:precise/logging-1")
   128  	s.AssertService(c, "logging", curl, 0, 0)
   129  }
   130  
   131  func (s *DeploySuite) TestConfig(c *gc.C) {
   132  	charmtesting.Charms.BundlePath(s.SeriesPath, "dummy")
   133  	path := setupConfigFile(c, c.MkDir())
   134  	err := runDeploy(c, "local:dummy", "dummy-service", "--config", path)
   135  	c.Assert(err, gc.IsNil)
   136  	service, err := s.State.Service("dummy-service")
   137  	c.Assert(err, gc.IsNil)
   138  	settings, err := service.ConfigSettings()
   139  	c.Assert(err, gc.IsNil)
   140  	c.Assert(settings, gc.DeepEquals, charm.Settings{
   141  		"skill-level": int64(9000),
   142  		"username":    "admin001",
   143  	})
   144  }
   145  
   146  func (s *DeploySuite) TestRelativeConfigPath(c *gc.C) {
   147  	charmtesting.Charms.BundlePath(s.SeriesPath, "dummy")
   148  	// Putting a config file in home is okay as $HOME is set to a tempdir
   149  	setupConfigFile(c, utils.Home())
   150  	err := runDeploy(c, "local:dummy", "dummy-service", "--config", "~/testconfig.yaml")
   151  	c.Assert(err, gc.IsNil)
   152  }
   153  
   154  func (s *DeploySuite) TestConfigError(c *gc.C) {
   155  	charmtesting.Charms.BundlePath(s.SeriesPath, "dummy")
   156  	path := setupConfigFile(c, c.MkDir())
   157  	err := runDeploy(c, "local:dummy", "other-service", "--config", path)
   158  	c.Assert(err, gc.ErrorMatches, `no settings found for "other-service"`)
   159  	_, err = s.State.Service("other-service")
   160  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   161  }
   162  
   163  func (s *DeploySuite) TestConstraints(c *gc.C) {
   164  	charmtesting.Charms.BundlePath(s.SeriesPath, "dummy")
   165  	err := runDeploy(c, "local:dummy", "--constraints", "mem=2G cpu-cores=2 networks=net1,^net2")
   166  	c.Assert(err, gc.IsNil)
   167  	curl := charm.MustParseURL("local:precise/dummy-1")
   168  	service, _ := s.AssertService(c, "dummy", curl, 1, 0)
   169  	cons, err := service.Constraints()
   170  	c.Assert(err, gc.IsNil)
   171  	c.Assert(cons, jc.DeepEquals, constraints.MustParse("mem=2G cpu-cores=2 networks=net1,^net2"))
   172  }
   173  
   174  func (s *DeploySuite) TestNetworks(c *gc.C) {
   175  	charmtesting.Charms.BundlePath(s.SeriesPath, "dummy")
   176  	err := runDeploy(c, "local:dummy", "--networks", ", net1, net2 , ", "--constraints", "mem=2G cpu-cores=2 networks=net1,net0,^net3,^net4")
   177  	c.Assert(err, gc.IsNil)
   178  	curl := charm.MustParseURL("local:precise/dummy-1")
   179  	service, _ := s.AssertService(c, "dummy", curl, 1, 0)
   180  	networks, err := service.Networks()
   181  	c.Assert(err, gc.IsNil)
   182  	c.Assert(networks, jc.DeepEquals, []string{"net1", "net2"})
   183  	cons, err := service.Constraints()
   184  	c.Assert(err, gc.IsNil)
   185  	c.Assert(cons, jc.DeepEquals, constraints.MustParse("mem=2G cpu-cores=2 networks=net1,net0,^net3,^net4"))
   186  }
   187  
   188  func (s *DeploySuite) TestSubordinateConstraints(c *gc.C) {
   189  	charmtesting.Charms.BundlePath(s.SeriesPath, "logging")
   190  	err := runDeploy(c, "local:logging", "--constraints", "mem=1G")
   191  	c.Assert(err, gc.ErrorMatches, "cannot use --constraints with subordinate service")
   192  }
   193  
   194  func (s *DeploySuite) TestNumUnits(c *gc.C) {
   195  	charmtesting.Charms.BundlePath(s.SeriesPath, "dummy")
   196  	err := runDeploy(c, "local:dummy", "-n", "13")
   197  	c.Assert(err, gc.IsNil)
   198  	curl := charm.MustParseURL("local:precise/dummy-1")
   199  	s.AssertService(c, "dummy", curl, 13, 0)
   200  }
   201  
   202  func (s *DeploySuite) TestNumUnitsSubordinate(c *gc.C) {
   203  	charmtesting.Charms.BundlePath(s.SeriesPath, "logging")
   204  	err := runDeploy(c, "--num-units", "3", "local:logging")
   205  	c.Assert(err, gc.ErrorMatches, "cannot use --num-units or --to with subordinate service")
   206  	_, err = s.State.Service("dummy")
   207  	c.Assert(err, gc.ErrorMatches, `service "dummy" not found`)
   208  }
   209  
   210  func (s *DeploySuite) assertForceMachine(c *gc.C, machineId string) {
   211  	svc, err := s.State.Service("portlandia")
   212  	c.Assert(err, gc.IsNil)
   213  	units, err := svc.AllUnits()
   214  	c.Assert(err, gc.IsNil)
   215  	c.Assert(units, gc.HasLen, 1)
   216  	mid, err := units[0].AssignedMachineId()
   217  	c.Assert(err, gc.IsNil)
   218  	c.Assert(mid, gc.Equals, machineId)
   219  }
   220  
   221  func (s *DeploySuite) TestForceMachine(c *gc.C) {
   222  	charmtesting.Charms.BundlePath(s.SeriesPath, "dummy")
   223  	machine, err := s.State.AddMachine("precise", state.JobHostUnits)
   224  	c.Assert(err, gc.IsNil)
   225  	err = runDeploy(c, "--to", machine.Id(), "local:dummy", "portlandia")
   226  	c.Assert(err, gc.IsNil)
   227  	s.assertForceMachine(c, machine.Id())
   228  }
   229  
   230  func (s *DeploySuite) TestForceMachineExistingContainer(c *gc.C) {
   231  	charmtesting.Charms.BundlePath(s.SeriesPath, "dummy")
   232  	template := state.MachineTemplate{
   233  		Series: "precise",
   234  		Jobs:   []state.MachineJob{state.JobHostUnits},
   235  	}
   236  	container, err := s.State.AddMachineInsideNewMachine(template, template, instance.LXC)
   237  	c.Assert(err, gc.IsNil)
   238  	err = runDeploy(c, "--to", container.Id(), "local:dummy", "portlandia")
   239  	c.Assert(err, gc.IsNil)
   240  	s.assertForceMachine(c, container.Id())
   241  	machines, err := s.State.AllMachines()
   242  	c.Assert(err, gc.IsNil)
   243  	c.Assert(machines, gc.HasLen, 2)
   244  }
   245  
   246  func (s *DeploySuite) TestForceMachineNewContainer(c *gc.C) {
   247  	charmtesting.Charms.BundlePath(s.SeriesPath, "dummy")
   248  	machine, err := s.State.AddMachine("precise", state.JobHostUnits)
   249  	c.Assert(err, gc.IsNil)
   250  	err = runDeploy(c, "--to", "lxc:"+machine.Id(), "local:dummy", "portlandia")
   251  	c.Assert(err, gc.IsNil)
   252  	s.assertForceMachine(c, machine.Id()+"/lxc/0")
   253  	machines, err := s.State.AllMachines()
   254  	c.Assert(err, gc.IsNil)
   255  	c.Assert(machines, gc.HasLen, 2)
   256  }
   257  
   258  func (s *DeploySuite) TestForceMachineNotFound(c *gc.C) {
   259  	charmtesting.Charms.BundlePath(s.SeriesPath, "dummy")
   260  	err := runDeploy(c, "--to", "42", "local:dummy", "portlandia")
   261  	c.Assert(err, gc.ErrorMatches, `cannot assign unit "portlandia/0" to machine: machine 42 not found`)
   262  	_, err = s.State.Service("dummy")
   263  	c.Assert(err, gc.ErrorMatches, `service "dummy" not found`)
   264  }
   265  
   266  func (s *DeploySuite) TestForceMachineSubordinate(c *gc.C) {
   267  	machine, err := s.State.AddMachine("precise", state.JobHostUnits)
   268  	c.Assert(err, gc.IsNil)
   269  	charmtesting.Charms.BundlePath(s.SeriesPath, "logging")
   270  	err = runDeploy(c, "--to", machine.Id(), "local:logging")
   271  	c.Assert(err, gc.ErrorMatches, "cannot use --num-units or --to with subordinate service")
   272  	_, err = s.State.Service("dummy")
   273  	c.Assert(err, gc.ErrorMatches, `service "dummy" not found`)
   274  }