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