github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/provider/manual/environ_test.go (about)

     1  // Copyright 2012 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package manual
     5  
     6  import (
     7  	"os"
     8  
     9  	"github.com/juju/errors"
    10  	"github.com/juju/testing"
    11  	jc "github.com/juju/testing/checkers"
    12  	"github.com/juju/utils/arch"
    13  	gc "gopkg.in/check.v1"
    14  
    15  	"github.com/juju/juju/core/constraints"
    16  	"github.com/juju/juju/core/instance"
    17  	"github.com/juju/juju/environs"
    18  	"github.com/juju/juju/environs/context"
    19  	"github.com/juju/juju/environs/manual/sshprovisioner"
    20  	coretesting "github.com/juju/juju/testing"
    21  )
    22  
    23  type baseEnvironSuite struct {
    24  	coretesting.FakeJujuXDGDataHomeSuite
    25  	env *manualEnviron
    26  
    27  	callCtx context.ProviderCallContext
    28  }
    29  
    30  func (s *baseEnvironSuite) SetUpTest(c *gc.C) {
    31  	s.FakeJujuXDGDataHomeSuite.SetUpTest(c)
    32  	env, err := ManualProvider{}.Open(environs.OpenParams{
    33  		Cloud:  CloudSpec(),
    34  		Config: MinimalConfig(c),
    35  	})
    36  	c.Assert(err, jc.ErrorIsNil)
    37  	s.env = env.(*manualEnviron)
    38  	s.callCtx = context.NewCloudCallContext()
    39  }
    40  
    41  type environSuite struct {
    42  	baseEnvironSuite
    43  }
    44  
    45  var _ = gc.Suite(&environSuite{})
    46  
    47  func (s *environSuite) TestInstances(c *gc.C) {
    48  	var ids []instance.Id
    49  
    50  	instances, err := s.env.Instances(s.callCtx, ids)
    51  	c.Assert(err, gc.Equals, environs.ErrNoInstances)
    52  	c.Assert(instances, gc.HasLen, 0)
    53  
    54  	ids = append(ids, BootstrapInstanceId)
    55  	instances, err = s.env.Instances(s.callCtx, ids)
    56  	c.Assert(err, jc.ErrorIsNil)
    57  	c.Assert(instances, gc.HasLen, 1)
    58  	c.Assert(instances[0], gc.NotNil)
    59  
    60  	ids = append(ids, BootstrapInstanceId)
    61  	instances, err = s.env.Instances(s.callCtx, ids)
    62  	c.Assert(err, jc.ErrorIsNil)
    63  	c.Assert(instances, gc.HasLen, 2)
    64  	c.Assert(instances[0], gc.NotNil)
    65  	c.Assert(instances[1], gc.NotNil)
    66  
    67  	ids = append(ids, instance.Id("invalid"))
    68  	instances, err = s.env.Instances(s.callCtx, ids)
    69  	c.Assert(err, gc.Equals, environs.ErrPartialInstances)
    70  	c.Assert(instances, gc.HasLen, 3)
    71  	c.Assert(instances[0], gc.NotNil)
    72  	c.Assert(instances[1], gc.NotNil)
    73  	c.Assert(instances[2], gc.IsNil)
    74  
    75  	ids = []instance.Id{instance.Id("invalid")}
    76  	instances, err = s.env.Instances(s.callCtx, ids)
    77  	c.Assert(err, gc.Equals, environs.ErrNoInstances)
    78  	c.Assert(instances, gc.HasLen, 1)
    79  	c.Assert(instances[0], gc.IsNil)
    80  }
    81  
    82  func (s *environSuite) TestDestroyController(c *gc.C) {
    83  	var resultStdout string
    84  	var resultErr error
    85  	runSSHCommandTesting := func(host string, command []string, stdin string) (string, string, error) {
    86  		c.Assert(host, gc.Equals, "ubuntu@hostname")
    87  		c.Assert(command, gc.DeepEquals, []string{"sudo", "/bin/bash"})
    88  		c.Assert(stdin, gc.Equals, `
    89  # Signal the jujud process to stop, then check it has done so before cleaning-up
    90  # after it.
    91  set -x
    92  touch '/var/lib/juju/uninstall-agent'
    93  
    94  stopped=0
    95  function wait_for_jujud {
    96      for i in {1..30}; do
    97          if pgrep jujud > /dev/null ; then
    98              sleep 1
    99          else
   100              echo jujud stopped
   101              stopped=1
   102              logger --id jujud stopped on attempt $i
   103              break
   104          fi
   105      done
   106  }
   107  
   108  # There might be no jujud at all (for example, after a failed deployment) so
   109  # don't require pkill to succeed before looking for a jujud process.
   110  # SIGABRT not SIGTERM, as abort lets the worker know it should uninstall itself,
   111  # rather than terminate normally.
   112  pkill -SIGABRT jujud
   113  wait_for_jujud
   114  
   115  [[ $stopped -ne 1 ]] && {
   116      # If jujud didn't stop nicely, we kill it hard here.
   117      pkill -SIGKILL jujud && wait_for_jujud
   118  }
   119  [[ $stopped -ne 1 ]] && {
   120      echo jujud removal failed
   121      logger --id $(ps -o pid,cmd,state -p $(pgrep jujud) | awk 'NR != 1 {printf("Process %d (%s) has state %s\n", $1, $2, $3)}')
   122      exit 1
   123  }
   124  service juju-db stop && logger --id stopped juju-db
   125  apt-get -y purge juju-mongo*
   126  apt-get -y autoremove
   127  rm -f /etc/init/juju*
   128  rm -f /etc/systemd/system{,/multi-user.target.wants}/juju*
   129  rm -fr '/var/lib/juju' '/var/log/juju'
   130  exit 0
   131  `)
   132  		return resultStdout, "", resultErr
   133  	}
   134  	s.PatchValue(&runSSHCommand, runSSHCommandTesting)
   135  	type test struct {
   136  		stdout string
   137  		err    error
   138  		match  string
   139  	}
   140  	tests := []test{
   141  		{"", nil, ""},
   142  		{"abc", nil, ""},
   143  		{"", errors.New("oh noes"), "oh noes"},
   144  	}
   145  	for i, t := range tests {
   146  		c.Logf("test %d: %v", i, t)
   147  		resultStdout, resultErr = t.stdout, t.err
   148  		err := s.env.DestroyController(s.callCtx, "controller-uuid")
   149  		if t.match == "" {
   150  			c.Assert(err, jc.ErrorIsNil)
   151  		} else {
   152  			c.Assert(err, gc.ErrorMatches, t.match)
   153  		}
   154  	}
   155  }
   156  
   157  func (s *environSuite) TestSupportsNetworking(c *gc.C) {
   158  	_, ok := environs.SupportsNetworking(s.env)
   159  	c.Assert(ok, jc.IsFalse)
   160  }
   161  
   162  func (s *environSuite) TestConstraintsValidator(c *gc.C) {
   163  	s.PatchValue(&sshprovisioner.DetectSeriesAndHardwareCharacteristics,
   164  		func(string) (instance.HardwareCharacteristics, string, error) {
   165  			amd64 := "amd64"
   166  			return instance.HardwareCharacteristics{
   167  				Arch: &amd64,
   168  			}, "", nil
   169  		},
   170  	)
   171  
   172  	validator, err := s.env.ConstraintsValidator(s.callCtx)
   173  	c.Assert(err, jc.ErrorIsNil)
   174  	cons := constraints.MustParse("arch=amd64 instance-type=foo tags=bar cpu-power=10 cores=2 mem=1G virt-type=kvm")
   175  	unsupported, err := validator.Validate(cons)
   176  	c.Assert(err, jc.ErrorIsNil)
   177  	c.Assert(unsupported, jc.SameContents, []string{"cpu-power", "instance-type", "tags", "virt-type"})
   178  }
   179  
   180  func (s *environSuite) TestConstraintsValidatorInsideController(c *gc.C) {
   181  	// Patch os.Args so it appears that we're running in "jujud", and then
   182  	// patch the host arch so it looks like we're running arm64.
   183  	s.PatchValue(&os.Args, []string{"/some/where/containing/jujud", "whatever"})
   184  	s.PatchValue(&arch.HostArch, func() string { return arch.ARM64 })
   185  
   186  	validator, err := s.env.ConstraintsValidator(s.callCtx)
   187  	c.Assert(err, jc.ErrorIsNil)
   188  	cons := constraints.MustParse("arch=arm64")
   189  	_, err = validator.Validate(cons)
   190  	c.Assert(err, jc.ErrorIsNil)
   191  }
   192  
   193  type controllerInstancesSuite struct {
   194  	baseEnvironSuite
   195  }
   196  
   197  var _ = gc.Suite(&controllerInstancesSuite{})
   198  
   199  func (s *controllerInstancesSuite) TestControllerInstances(c *gc.C) {
   200  	var outputResult string
   201  	var errResult error
   202  	runSSHCommandTesting := func(host string, command []string, stdin string) (string, string, error) {
   203  		return outputResult, "", errResult
   204  	}
   205  	s.PatchValue(&runSSHCommand, runSSHCommandTesting)
   206  
   207  	type test struct {
   208  		output      string
   209  		err         error
   210  		expectedErr string
   211  	}
   212  	tests := []test{{
   213  		output: "",
   214  	}, {
   215  		output:      "no-agent-dir",
   216  		expectedErr: "model is not bootstrapped",
   217  	}, {
   218  		output:      "woo",
   219  		expectedErr: `unexpected output: "woo"`,
   220  	}, {
   221  		err:         errors.New("an error"),
   222  		expectedErr: "an error",
   223  	}}
   224  
   225  	for i, test := range tests {
   226  		c.Logf("test %d", i)
   227  		outputResult = test.output
   228  		errResult = test.err
   229  		instances, err := s.env.ControllerInstances(s.callCtx, "not-used")
   230  		if test.expectedErr == "" {
   231  			c.Assert(err, jc.ErrorIsNil)
   232  			c.Assert(instances, gc.DeepEquals, []instance.Id{BootstrapInstanceId})
   233  		} else {
   234  			c.Assert(err, gc.ErrorMatches, test.expectedErr)
   235  			c.Assert(instances, gc.HasLen, 0)
   236  		}
   237  	}
   238  }
   239  
   240  func (s *controllerInstancesSuite) TestControllerInstancesStderr(c *gc.C) {
   241  	// Stderr should not affect the behaviour of ControllerInstances.
   242  	testing.PatchExecutable(c, s, "ssh", "#!/bin/sh\nhead -n1 > /dev/null; echo abc >&2; exit 0")
   243  	_, err := s.env.ControllerInstances(s.callCtx, "not-used")
   244  	c.Assert(err, jc.ErrorIsNil)
   245  }
   246  
   247  func (s *controllerInstancesSuite) TestControllerInstancesError(c *gc.C) {
   248  	// If the ssh execution fails, its stderr will be captured in the error message.
   249  	testing.PatchExecutable(c, s, "ssh", "#!/bin/sh\nhead -n1 > /dev/null; echo abc >&2; exit 1")
   250  	_, err := s.env.ControllerInstances(s.callCtx, "not-used")
   251  	c.Assert(err, gc.ErrorMatches, "abc: .*")
   252  }
   253  
   254  func (s *controllerInstancesSuite) TestControllerInstancesInternal(c *gc.C) {
   255  	// Patch os.Args so it appears that we're running in "jujud".
   256  	s.PatchValue(&os.Args, []string{"/some/where/containing/jujud", "whatever"})
   257  	// Patch the ssh executable so that it would cause an error if we
   258  	// were to call it.
   259  	testing.PatchExecutable(c, s, "ssh", "#!/bin/sh\nhead -n1 > /dev/null; echo abc >&2; exit 1")
   260  	instances, err := s.env.ControllerInstances(s.callCtx, "not-used")
   261  	c.Assert(err, jc.ErrorIsNil)
   262  	c.Assert(instances, gc.DeepEquals, []instance.Id{BootstrapInstanceId})
   263  }