github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/cmd/juju/machine/add_test.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package machine_test
     5  
     6  import (
     7  	"strconv"
     8  	"strings"
     9  
    10  	"github.com/juju/cmd"
    11  	"github.com/juju/errors"
    12  	jc "github.com/juju/testing/checkers"
    13  	gc "gopkg.in/check.v1"
    14  
    15  	"github.com/juju/juju/apiserver/common"
    16  	"github.com/juju/juju/apiserver/params"
    17  	"github.com/juju/juju/cmd/envcmd"
    18  	"github.com/juju/juju/cmd/juju/machine"
    19  	"github.com/juju/juju/environs/manual"
    20  	"github.com/juju/juju/state/multiwatcher"
    21  	"github.com/juju/juju/storage"
    22  	"github.com/juju/juju/testing"
    23  )
    24  
    25  type AddMachineSuite struct {
    26  	testing.FakeJujuHomeSuite
    27  	fakeAddMachine     *fakeAddMachineAPI
    28  	fakeMachineManager *fakeMachineManagerAPI
    29  }
    30  
    31  var _ = gc.Suite(&AddMachineSuite{})
    32  
    33  func (s *AddMachineSuite) SetUpTest(c *gc.C) {
    34  	s.FakeJujuHomeSuite.SetUpTest(c)
    35  	s.fakeAddMachine = &fakeAddMachineAPI{}
    36  	s.fakeAddMachine.agentVersion = "1.21.0"
    37  	s.fakeMachineManager = &fakeMachineManagerAPI{}
    38  }
    39  
    40  func (s *AddMachineSuite) TestInit(c *gc.C) {
    41  	for i, test := range []struct {
    42  		args        []string
    43  		series      string
    44  		constraints string
    45  		placement   string
    46  		count       int
    47  		errorString string
    48  	}{
    49  		{
    50  			count: 1,
    51  		}, {
    52  			args:   []string{"--series", "some-series"},
    53  			count:  1,
    54  			series: "some-series",
    55  		}, {
    56  			args:  []string{"-n", "2"},
    57  			count: 2,
    58  		}, {
    59  			args:      []string{"lxc"},
    60  			count:     1,
    61  			placement: "lxc:",
    62  		}, {
    63  			args:      []string{"lxc", "-n", "2"},
    64  			count:     2,
    65  			placement: "lxc:",
    66  		}, {
    67  			args:      []string{"lxc:4"},
    68  			count:     1,
    69  			placement: "lxc:4",
    70  		}, {
    71  			args:        []string{"--constraints", "mem=8G"},
    72  			count:       1,
    73  			constraints: "mem=8192M",
    74  		}, {
    75  			args:        []string{"--constraints", "container=lxc"},
    76  			errorString: `container constraint "lxc" not allowed when adding a machine`,
    77  		}, {
    78  			args:      []string{"ssh:user@10.10.0.3"},
    79  			count:     1,
    80  			placement: "ssh:user@10.10.0.3",
    81  		}, {
    82  			args:      []string{"zone=us-east-1a"},
    83  			count:     1,
    84  			placement: "env-uuid:zone=us-east-1a",
    85  		}, {
    86  			args:      []string{"anything-here"},
    87  			count:     1,
    88  			placement: "env-uuid:anything-here",
    89  		}, {
    90  			args:        []string{"anything", "else"},
    91  			errorString: `unrecognized args: \["else"\]`,
    92  		}, {
    93  			args:      []string{"something:special"},
    94  			count:     1,
    95  			placement: "something:special",
    96  		},
    97  	} {
    98  		c.Logf("test %d", i)
    99  		addCmd := &machine.AddCommand{}
   100  		err := testing.InitCommand(addCmd, test.args)
   101  		if test.errorString == "" {
   102  			c.Check(err, jc.ErrorIsNil)
   103  			c.Check(addCmd.Series, gc.Equals, test.series)
   104  			c.Check(addCmd.Constraints.String(), gc.Equals, test.constraints)
   105  			if addCmd.Placement != nil {
   106  				c.Check(addCmd.Placement.String(), gc.Equals, test.placement)
   107  			} else {
   108  				c.Check("", gc.Equals, test.placement)
   109  			}
   110  			c.Check(addCmd.NumMachines, gc.Equals, test.count)
   111  		} else {
   112  			c.Check(err, gc.ErrorMatches, test.errorString)
   113  		}
   114  	}
   115  }
   116  
   117  func (s *AddMachineSuite) run(c *gc.C, args ...string) (*cmd.Context, error) {
   118  	add := machine.NewAddCommand(s.fakeAddMachine, s.fakeMachineManager)
   119  	return testing.RunCommand(c, envcmd.Wrap(add), args...)
   120  }
   121  
   122  func (s *AddMachineSuite) TestAddMachine(c *gc.C) {
   123  	context, err := s.run(c)
   124  	c.Assert(err, jc.ErrorIsNil)
   125  	c.Assert(testing.Stderr(context), gc.Equals, "created machine 0\n")
   126  
   127  	c.Assert(s.fakeAddMachine.args, gc.HasLen, 1)
   128  	param := s.fakeAddMachine.args[0]
   129  	c.Assert(param.Jobs, jc.DeepEquals, []multiwatcher.MachineJob{
   130  		multiwatcher.JobHostUnits,
   131  		multiwatcher.JobManageNetworking,
   132  	})
   133  }
   134  
   135  func (s *AddMachineSuite) TestSSHPlacement(c *gc.C) {
   136  	s.PatchValue(machine.ManualProvisioner, func(args manual.ProvisionMachineArgs) (string, error) {
   137  		return "42", nil
   138  	})
   139  	context, err := s.run(c, "ssh:10.1.2.3")
   140  	c.Assert(err, jc.ErrorIsNil)
   141  	c.Assert(testing.Stderr(context), gc.Equals, "created machine 42\n")
   142  }
   143  
   144  func (s *AddMachineSuite) TestSSHPlacementError(c *gc.C) {
   145  	s.PatchValue(machine.ManualProvisioner, func(args manual.ProvisionMachineArgs) (string, error) {
   146  		return "", errors.New("failed to initialize warp core")
   147  	})
   148  	context, err := s.run(c, "ssh:10.1.2.3")
   149  	c.Assert(err, gc.ErrorMatches, "failed to initialize warp core")
   150  	c.Assert(testing.Stderr(context), gc.Equals, "")
   151  }
   152  
   153  func (s *AddMachineSuite) TestParamsPassedOn(c *gc.C) {
   154  	_, err := s.run(c, "--constraints", "mem=8G", "--series=special", "zone=nz")
   155  	c.Assert(err, jc.ErrorIsNil)
   156  	c.Assert(s.fakeAddMachine.args, gc.HasLen, 1)
   157  	param := s.fakeAddMachine.args[0]
   158  	c.Assert(param.Placement.String(), gc.Equals, "fake-uuid:zone=nz")
   159  	c.Assert(param.Series, gc.Equals, "special")
   160  	c.Assert(param.Constraints.String(), gc.Equals, "mem=8192M")
   161  }
   162  
   163  func (s *AddMachineSuite) TestParamsPassedOnNTimes(c *gc.C) {
   164  	_, err := s.run(c, "-n", "3", "--constraints", "mem=8G", "--series=special")
   165  	c.Assert(err, jc.ErrorIsNil)
   166  	c.Assert(s.fakeAddMachine.args, gc.HasLen, 3)
   167  	param := s.fakeAddMachine.args[0]
   168  	c.Assert(param.Series, gc.Equals, "special")
   169  	c.Assert(param.Constraints.String(), gc.Equals, "mem=8192M")
   170  	c.Assert(s.fakeAddMachine.args[0], jc.DeepEquals, s.fakeAddMachine.args[1])
   171  	c.Assert(s.fakeAddMachine.args[0], jc.DeepEquals, s.fakeAddMachine.args[2])
   172  }
   173  
   174  func (s *AddMachineSuite) TestAddThreeMachinesWithTwoFailures(c *gc.C) {
   175  	s.fakeAddMachine.successOrder = []bool{true, false, false}
   176  	expectedOutput := `created machine 0
   177  failed to create 2 machines
   178  `
   179  	context, err := s.run(c, "-n", "3")
   180  	c.Assert(err, gc.ErrorMatches, "something went wrong, something went wrong")
   181  	c.Assert(testing.Stderr(context), gc.Equals, expectedOutput)
   182  }
   183  
   184  func (s *AddMachineSuite) TestBlockedError(c *gc.C) {
   185  	s.fakeAddMachine.addError = common.ErrOperationBlocked("TestBlockedError")
   186  	_, err := s.run(c)
   187  	c.Assert(err, gc.Equals, cmd.ErrSilent)
   188  	// msg is logged
   189  	stripped := strings.Replace(c.GetTestLog(), "\n", "", -1)
   190  	c.Check(stripped, gc.Matches, ".*TestBlockedError.*")
   191  }
   192  
   193  func (s *AddMachineSuite) TestServerIsPreJobManageNetworking(c *gc.C) {
   194  	s.fakeAddMachine.agentVersion = "1.18.1"
   195  	_, err := s.run(c)
   196  	c.Assert(err, jc.ErrorIsNil)
   197  
   198  	c.Assert(s.fakeAddMachine.args, gc.HasLen, 1)
   199  	param := s.fakeAddMachine.args[0]
   200  	c.Assert(param.Jobs, jc.DeepEquals, []multiwatcher.MachineJob{
   201  		multiwatcher.JobHostUnits,
   202  	})
   203  }
   204  
   205  func (s *AddMachineSuite) TestAddMachineWithDisks(c *gc.C) {
   206  	s.fakeMachineManager.apiVersion = 1
   207  	_, err := s.run(c, "--disks", "2,1G", "--disks", "2G")
   208  	c.Assert(err, jc.ErrorIsNil)
   209  	c.Assert(s.fakeAddMachine.args, gc.HasLen, 0)
   210  	c.Assert(s.fakeMachineManager.args, gc.HasLen, 1)
   211  	param := s.fakeMachineManager.args[0]
   212  	c.Assert(param.Disks, gc.DeepEquals, []storage.Constraints{
   213  		{Size: 1024, Count: 2},
   214  		{Size: 2048, Count: 1},
   215  	})
   216  }
   217  
   218  func (s *AddMachineSuite) TestAddMachineWithDisksUnsupported(c *gc.C) {
   219  	_, err := s.run(c, "--disks", "2,1G", "--disks", "2G")
   220  	c.Assert(err, gc.ErrorMatches, "cannot add machines with disks: not supported by the API server")
   221  }
   222  
   223  type fakeAddMachineAPI struct {
   224  	successOrder []bool
   225  	currentOp    int
   226  	args         []params.AddMachineParams
   227  	addError     error
   228  	agentVersion interface{}
   229  }
   230  
   231  func (f *fakeAddMachineAPI) Close() error {
   232  	return nil
   233  }
   234  
   235  func (f *fakeAddMachineAPI) EnvironmentUUID() string {
   236  	return "fake-uuid"
   237  }
   238  
   239  func (f *fakeAddMachineAPI) AddMachines(args []params.AddMachineParams) ([]params.AddMachinesResult, error) {
   240  	if f.addError != nil {
   241  		return nil, f.addError
   242  	}
   243  	results := []params.AddMachinesResult{}
   244  	for i := range args {
   245  		f.args = append(f.args, args[i])
   246  		if i >= len(f.successOrder) || f.successOrder[i] {
   247  			results = append(results, params.AddMachinesResult{
   248  				Machine: strconv.Itoa(i),
   249  				Error:   nil,
   250  			})
   251  		} else {
   252  			results = append(results, params.AddMachinesResult{
   253  				Machine: string(i),
   254  				Error:   &params.Error{"something went wrong", "1"},
   255  			})
   256  		}
   257  		f.currentOp++
   258  	}
   259  	return results, nil
   260  }
   261  
   262  func (f *fakeAddMachineAPI) AddMachines1dot18(args []params.AddMachineParams) ([]params.AddMachinesResult, error) {
   263  	return f.AddMachines(args)
   264  }
   265  
   266  func (f *fakeAddMachineAPI) ForceDestroyMachines(machines ...string) error {
   267  	return errors.NotImplementedf("ForceDestroyMachines")
   268  }
   269  
   270  func (f *fakeAddMachineAPI) ProvisioningScript(params.ProvisioningScriptParams) (script string, err error) {
   271  	return "", errors.NotImplementedf("ProvisioningScript")
   272  }
   273  
   274  func (f *fakeAddMachineAPI) EnvironmentGet() (map[string]interface{}, error) {
   275  	return map[string]interface{}{"agent-version": f.agentVersion}, nil
   276  }
   277  
   278  type fakeMachineManagerAPI struct {
   279  	apiVersion int
   280  	fakeAddMachineAPI
   281  }
   282  
   283  func (f *fakeMachineManagerAPI) BestAPIVersion() int {
   284  	return f.apiVersion
   285  }