github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/cmd/juju/addunit_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  	jc "github.com/juju/testing/checkers"
    11  	gc "gopkg.in/check.v1"
    12  	"gopkg.in/juju/charm.v4"
    13  
    14  	"github.com/juju/juju/api"
    15  	"github.com/juju/juju/cmd/envcmd"
    16  	"github.com/juju/juju/environs/config"
    17  	"github.com/juju/juju/instance"
    18  	jujutesting "github.com/juju/juju/juju/testing"
    19  	"github.com/juju/juju/state"
    20  	"github.com/juju/juju/testcharms"
    21  	"github.com/juju/juju/testing"
    22  )
    23  
    24  type AddUnitSuite struct {
    25  	jujutesting.RepoSuite
    26  }
    27  
    28  var _ = gc.Suite(&AddUnitSuite{})
    29  
    30  var initAddUnitErrorTests = []struct {
    31  	args []string
    32  	err  string
    33  }{
    34  	{
    35  		args: []string{"some-service-name", "-n", "0"},
    36  		err:  `--num-units must be a positive integer`,
    37  	}, {
    38  		args: []string{"some-service-name", "--to", "bigglesplop"},
    39  		err:  `invalid --to parameter "bigglesplop"`,
    40  	}, {
    41  		args: []string{"some-service-name", "-n", "2", "--to", "123"},
    42  		err:  `cannot use --num-units > 1 with --to`,
    43  	},
    44  }
    45  
    46  func (s *AddUnitSuite) TestInitErrors(c *gc.C) {
    47  	for i, t := range initAddUnitErrorTests {
    48  		c.Logf("test %d", i)
    49  		err := testing.InitCommand(envcmd.Wrap(&AddUnitCommand{}), t.args)
    50  		c.Check(err, gc.ErrorMatches, t.err)
    51  	}
    52  }
    53  
    54  func runAddUnit(c *gc.C, args ...string) error {
    55  	_, err := testing.RunCommand(c, envcmd.Wrap(&AddUnitCommand{}), args...)
    56  	return err
    57  }
    58  
    59  func (s *AddUnitSuite) setupService(c *gc.C) *charm.URL {
    60  	testcharms.Repo.CharmArchivePath(s.SeriesPath, "dummy")
    61  	err := runDeploy(c, "local:dummy", "some-service-name")
    62  	c.Assert(err, jc.ErrorIsNil)
    63  	curl := charm.MustParseURL("local:trusty/dummy-1")
    64  	s.AssertService(c, "some-service-name", curl, 1, 0)
    65  	return curl
    66  }
    67  
    68  func (s *AddUnitSuite) TestAddUnit(c *gc.C) {
    69  	curl := s.setupService(c)
    70  
    71  	err := runAddUnit(c, "some-service-name")
    72  	c.Assert(err, jc.ErrorIsNil)
    73  	s.AssertService(c, "some-service-name", curl, 2, 0)
    74  
    75  	err = runAddUnit(c, "--num-units", "2", "some-service-name")
    76  	c.Assert(err, jc.ErrorIsNil)
    77  	s.AssertService(c, "some-service-name", curl, 4, 0)
    78  }
    79  
    80  func (s *AddUnitSuite) TestBlockAddUnit(c *gc.C) {
    81  	s.setupService(c)
    82  
    83  	// Block operation
    84  	s.AssertConfigParameterUpdated(c, "block-all-changes", true)
    85  	c.Assert(runAddUnit(c, "some-service-name"), gc.ErrorMatches, cmd.ErrSilent.Error())
    86  
    87  	// msg is logged
    88  	stripped := strings.Replace(c.GetTestLog(), "\n", "", -1)
    89  	c.Check(stripped, gc.Matches, ".*To unblock changes.*")
    90  }
    91  
    92  // assertForceMachine ensures that the result of assigning a unit with --to
    93  // is as expected.
    94  func (s *AddUnitSuite) assertForceMachine(c *gc.C, svc *state.Service, expectedNumMachines, unitNum int, machineId string) {
    95  	units, err := svc.AllUnits()
    96  	c.Assert(err, jc.ErrorIsNil)
    97  	c.Assert(units, gc.HasLen, expectedNumMachines)
    98  	mid, err := units[unitNum].AssignedMachineId()
    99  	c.Assert(err, jc.ErrorIsNil)
   100  	c.Assert(mid, gc.Equals, machineId)
   101  }
   102  
   103  func (s *AddUnitSuite) TestForceMachine(c *gc.C) {
   104  	curl := s.setupService(c)
   105  	machine, err := s.State.AddMachine(testing.FakeDefaultSeries, state.JobHostUnits)
   106  	c.Assert(err, jc.ErrorIsNil)
   107  	machine2, err := s.State.AddMachine(testing.FakeDefaultSeries, state.JobHostUnits)
   108  	c.Assert(err, jc.ErrorIsNil)
   109  
   110  	err = runAddUnit(c, "some-service-name", "--to", machine2.Id())
   111  	c.Assert(err, jc.ErrorIsNil)
   112  	err = runAddUnit(c, "some-service-name", "--to", machine.Id())
   113  	c.Assert(err, jc.ErrorIsNil)
   114  	svc, _ := s.AssertService(c, "some-service-name", curl, 3, 0)
   115  	s.assertForceMachine(c, svc, 3, 1, machine2.Id())
   116  	s.assertForceMachine(c, svc, 3, 2, machine.Id())
   117  }
   118  
   119  func (s *AddUnitSuite) TestBlockForceMachine(c *gc.C) {
   120  	curl := s.setupService(c)
   121  	machine, err := s.State.AddMachine(testing.FakeDefaultSeries, state.JobHostUnits)
   122  	c.Assert(err, jc.ErrorIsNil)
   123  	machine2, err := s.State.AddMachine(testing.FakeDefaultSeries, state.JobHostUnits)
   124  	c.Assert(err, jc.ErrorIsNil)
   125  
   126  	err = runAddUnit(c, "some-service-name", "--to", machine2.Id())
   127  	c.Assert(err, jc.ErrorIsNil)
   128  	err = runAddUnit(c, "some-service-name", "--to", machine.Id())
   129  	c.Assert(err, jc.ErrorIsNil)
   130  	svc, _ := s.AssertService(c, "some-service-name", curl, 3, 0)
   131  	// Block operation: should be ignored :)
   132  	s.AssertConfigParameterUpdated(c, "block-all-changes", true)
   133  	s.assertForceMachine(c, svc, 3, 1, machine2.Id())
   134  	s.assertForceMachine(c, svc, 3, 2, machine.Id())
   135  }
   136  
   137  func (s *AddUnitSuite) TestForceMachineExistingContainer(c *gc.C) {
   138  	curl := s.setupService(c)
   139  	machine, err := s.State.AddMachine(testing.FakeDefaultSeries, state.JobHostUnits)
   140  	c.Assert(err, jc.ErrorIsNil)
   141  	template := state.MachineTemplate{
   142  		Series: testing.FakeDefaultSeries,
   143  		Jobs:   []state.MachineJob{state.JobHostUnits},
   144  	}
   145  	container, err := s.State.AddMachineInsideMachine(template, machine.Id(), instance.LXC)
   146  	c.Assert(err, jc.ErrorIsNil)
   147  
   148  	err = runAddUnit(c, "some-service-name", "--to", container.Id())
   149  	c.Assert(err, jc.ErrorIsNil)
   150  	err = runAddUnit(c, "some-service-name", "--to", machine.Id())
   151  	c.Assert(err, jc.ErrorIsNil)
   152  	svc, _ := s.AssertService(c, "some-service-name", curl, 3, 0)
   153  	s.assertForceMachine(c, svc, 3, 1, container.Id())
   154  	s.assertForceMachine(c, svc, 3, 2, machine.Id())
   155  }
   156  
   157  func (s *AddUnitSuite) TestForceMachineNewContainer(c *gc.C) {
   158  	curl := s.setupService(c)
   159  	machine, err := s.State.AddMachine(testing.FakeDefaultSeries, state.JobHostUnits)
   160  	c.Assert(err, jc.ErrorIsNil)
   161  
   162  	err = runAddUnit(c, "some-service-name", "--to", "lxc:"+machine.Id())
   163  	c.Assert(err, jc.ErrorIsNil)
   164  	err = runAddUnit(c, "some-service-name", "--to", machine.Id())
   165  	c.Assert(err, jc.ErrorIsNil)
   166  	svc, _ := s.AssertService(c, "some-service-name", curl, 3, 0)
   167  	s.assertForceMachine(c, svc, 3, 1, machine.Id()+"/lxc/0")
   168  	s.assertForceMachine(c, svc, 3, 2, machine.Id())
   169  }
   170  
   171  func (s *AddUnitSuite) TestNonLocalCannotHostUnits(c *gc.C) {
   172  	err := runAddUnit(c, "some-service-name", "--to", "0")
   173  	c.Assert(err, gc.Not(gc.ErrorMatches), "machine 0 is the state server for a local environment and cannot host units")
   174  }
   175  
   176  func (s *AddUnitSuite) TestBlockNonLocalCannotHostUnits(c *gc.C) {
   177  	// Block operation
   178  	s.AssertConfigParameterUpdated(c, "block-all-changes", true)
   179  	c.Assert(runAddUnit(c, "some-service-name", "--to", "0"), gc.ErrorMatches, cmd.ErrSilent.Error())
   180  
   181  	// msg is logged
   182  	stripped := strings.Replace(c.GetTestLog(), "\n", "", -1)
   183  	c.Check(stripped, gc.Matches, ".*To unblock changes.*")
   184  }
   185  
   186  func (s *AddUnitSuite) TestCannotDeployToNonExistentMachine(c *gc.C) {
   187  	s.setupService(c)
   188  	err := runAddUnit(c, "some-service-name", "--to", "42")
   189  	c.Assert(err, gc.ErrorMatches, `cannot add units for service "some-service-name" to machine 42: machine 42 not found`)
   190  }
   191  
   192  func (s *AddUnitSuite) TestBlockCannotDeployToNonExistentMachine(c *gc.C) {
   193  	s.setupService(c)
   194  	// Block operation
   195  	s.AssertConfigParameterUpdated(c, "block-all-changes", true)
   196  	c.Assert(runAddUnit(c, "some-service-name", "--to", "42"), gc.ErrorMatches, cmd.ErrSilent.Error())
   197  
   198  	// msg is logged
   199  	stripped := strings.Replace(c.GetTestLog(), "\n", "", -1)
   200  	c.Check(stripped, gc.Matches, ".*To unblock changes.*")
   201  }
   202  
   203  type AddUnitLocalSuite struct {
   204  	jujutesting.RepoSuite
   205  }
   206  
   207  var _ = gc.Suite(&AddUnitLocalSuite{})
   208  
   209  func (s *AddUnitLocalSuite) SetUpTest(c *gc.C) {
   210  	s.RepoSuite.SetUpTest(c)
   211  
   212  	// override provider type
   213  	s.PatchValue(&getClientConfig, func(client *api.Client) (*config.Config, error) {
   214  		attrs, err := client.EnvironmentGet()
   215  		if err != nil {
   216  			return nil, err
   217  		}
   218  		attrs["type"] = "local"
   219  		return config.New(config.NoDefaults, attrs)
   220  	})
   221  }
   222  
   223  func (s *AddUnitLocalSuite) TestLocalCannotHostUnits(c *gc.C) {
   224  	err := runAddUnit(c, "some-service-name", "--to", "0")
   225  	c.Assert(err, gc.ErrorMatches, "machine 0 is the state server for a local environment and cannot host units")
   226  }
   227  
   228  type namesSuite struct {
   229  }
   230  
   231  var _ = gc.Suite(&namesSuite{})
   232  
   233  func (*namesSuite) TestNameChecks(c *gc.C) {
   234  	assertMachineOrNewContainer := func(s string, expect bool) {
   235  		c.Logf("%s -> %v", s, expect)
   236  		c.Assert(isMachineOrNewContainer(s), gc.Equals, expect)
   237  	}
   238  	assertMachineOrNewContainer("0", true)
   239  	assertMachineOrNewContainer("00", false)
   240  	assertMachineOrNewContainer("1", true)
   241  	assertMachineOrNewContainer("0/lxc/0", true)
   242  	assertMachineOrNewContainer("lxc:0", true)
   243  	assertMachineOrNewContainer("lxc:lxc:0", false)
   244  	assertMachineOrNewContainer("kvm:0/lxc/1", true)
   245  	assertMachineOrNewContainer("lxc:", false)
   246  	assertMachineOrNewContainer(":lxc", false)
   247  	assertMachineOrNewContainer("0/lxc/", false)
   248  	assertMachineOrNewContainer("0/lxc", false)
   249  	assertMachineOrNewContainer("kvm:0/lxc", false)
   250  	assertMachineOrNewContainer("0/lxc/01", false)
   251  	assertMachineOrNewContainer("0/lxc/10", true)
   252  	assertMachineOrNewContainer("0/kvm/4", true)
   253  }