github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/worker/provisioner/kvm-broker_test.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package provisioner_test
     5  
     6  import (
     7  	"fmt"
     8  	"path/filepath"
     9  	"runtime"
    10  	"time"
    11  
    12  	"github.com/juju/errors"
    13  	"github.com/juju/names"
    14  	gitjujutesting "github.com/juju/testing"
    15  	jc "github.com/juju/testing/checkers"
    16  	gc "gopkg.in/check.v1"
    17  
    18  	"github.com/juju/juju/agent"
    19  	"github.com/juju/juju/cloudconfig/instancecfg"
    20  	"github.com/juju/juju/constraints"
    21  	"github.com/juju/juju/container"
    22  	"github.com/juju/juju/container/kvm/mock"
    23  	kvmtesting "github.com/juju/juju/container/kvm/testing"
    24  	"github.com/juju/juju/environs"
    25  	"github.com/juju/juju/feature"
    26  	"github.com/juju/juju/instance"
    27  	instancetest "github.com/juju/juju/instance/testing"
    28  	jujutesting "github.com/juju/juju/juju/testing"
    29  	"github.com/juju/juju/state"
    30  	coretesting "github.com/juju/juju/testing"
    31  	coretools "github.com/juju/juju/tools"
    32  	"github.com/juju/juju/version"
    33  	"github.com/juju/juju/worker/provisioner"
    34  )
    35  
    36  type kvmSuite struct {
    37  	kvmtesting.TestSuite
    38  	events     chan mock.Event
    39  	eventsDone chan struct{}
    40  }
    41  
    42  type kvmBrokerSuite struct {
    43  	kvmSuite
    44  	broker      environs.InstanceBroker
    45  	agentConfig agent.Config
    46  	api         *fakeAPI
    47  }
    48  
    49  var _ = gc.Suite(&kvmBrokerSuite{})
    50  
    51  func (s *kvmSuite) SetUpTest(c *gc.C) {
    52  	if runtime.GOOS == "windows" {
    53  		c.Skip("Skipping kvm tests on windows")
    54  	}
    55  	s.TestSuite.SetUpTest(c)
    56  	s.events = make(chan mock.Event)
    57  	s.eventsDone = make(chan struct{})
    58  	go func() {
    59  		defer close(s.eventsDone)
    60  		for event := range s.events {
    61  			c.Output(3, fmt.Sprintf("kvm event: <%s, %s>", event.Action, event.InstanceId))
    62  		}
    63  	}()
    64  	s.TestSuite.ContainerFactory.AddListener(s.events)
    65  }
    66  
    67  func (s *kvmSuite) TearDownTest(c *gc.C) {
    68  	close(s.events)
    69  	<-s.eventsDone
    70  	s.TestSuite.TearDownTest(c)
    71  }
    72  
    73  func (s *kvmBrokerSuite) SetUpTest(c *gc.C) {
    74  	if runtime.GOOS == "windows" {
    75  		c.Skip("Skipping kvm tests on windows")
    76  	}
    77  	s.kvmSuite.SetUpTest(c)
    78  	var err error
    79  	s.agentConfig, err = agent.NewAgentConfig(
    80  		agent.AgentConfigParams{
    81  			DataDir:           "/not/used/here",
    82  			Tag:               names.NewUnitTag("ubuntu/1"),
    83  			UpgradedToVersion: version.Current.Number,
    84  			Password:          "dummy-secret",
    85  			Nonce:             "nonce",
    86  			APIAddresses:      []string{"10.0.0.1:1234"},
    87  			CACert:            coretesting.CACert,
    88  			Environment:       coretesting.EnvironmentTag,
    89  		})
    90  	c.Assert(err, jc.ErrorIsNil)
    91  	s.api = NewFakeAPI()
    92  	managerConfig := container.ManagerConfig{container.ConfigName: "juju"}
    93  	s.broker, err = provisioner.NewKvmBroker(s.api, s.agentConfig, managerConfig, false)
    94  	c.Assert(err, jc.ErrorIsNil)
    95  }
    96  
    97  func (s *kvmBrokerSuite) startInstance(c *gc.C, machineId string) instance.Instance {
    98  	machineNonce := "fake-nonce"
    99  	stateInfo := jujutesting.FakeStateInfo(machineId)
   100  	apiInfo := jujutesting.FakeAPIInfo(machineId)
   101  	instanceConfig, err := instancecfg.NewInstanceConfig(machineId, machineNonce, "released", "quantal", true, nil, stateInfo, apiInfo)
   102  	c.Assert(err, jc.ErrorIsNil)
   103  	cons := constraints.Value{}
   104  	possibleTools := coretools.List{&coretools.Tools{
   105  		Version: version.MustParseBinary("2.3.4-quantal-amd64"),
   106  		URL:     "http://tools.testing.invalid/2.3.4-quantal-amd64.tgz",
   107  	}}
   108  	result, err := s.broker.StartInstance(environs.StartInstanceParams{
   109  		Constraints:    cons,
   110  		Tools:          possibleTools,
   111  		InstanceConfig: instanceConfig,
   112  	})
   113  	c.Assert(err, jc.ErrorIsNil)
   114  	return result.Instance
   115  }
   116  
   117  func (s *kvmBrokerSuite) maintainInstance(c *gc.C, machineId string) {
   118  	machineNonce := "fake-nonce"
   119  	stateInfo := jujutesting.FakeStateInfo(machineId)
   120  	apiInfo := jujutesting.FakeAPIInfo(machineId)
   121  	instanceConfig, err := instancecfg.NewInstanceConfig(machineId, machineNonce, "released", "quantal", true, nil, stateInfo, apiInfo)
   122  	c.Assert(err, jc.ErrorIsNil)
   123  	cons := constraints.Value{}
   124  	possibleTools := coretools.List{&coretools.Tools{
   125  		Version: version.MustParseBinary("2.3.4-quantal-amd64"),
   126  		URL:     "http://tools.testing.invalid/2.3.4-quantal-amd64.tgz",
   127  	}}
   128  	err = s.broker.MaintainInstance(environs.StartInstanceParams{
   129  		Constraints:    cons,
   130  		Tools:          possibleTools,
   131  		InstanceConfig: instanceConfig,
   132  	})
   133  	c.Assert(err, jc.ErrorIsNil)
   134  }
   135  
   136  func (s *kvmBrokerSuite) TestStartInstance(c *gc.C) {
   137  	machineId := "1/kvm/0"
   138  	s.SetFeatureFlags(feature.AddressAllocation)
   139  	kvm := s.startInstance(c, machineId)
   140  	s.api.CheckCalls(c, []gitjujutesting.StubCall{{
   141  		FuncName: "PrepareContainerInterfaceInfo",
   142  		Args:     []interface{}{names.NewMachineTag("1-kvm-0")},
   143  	}, {
   144  		FuncName: "ContainerConfig",
   145  	}})
   146  	c.Assert(kvm.Id(), gc.Equals, instance.Id("juju-machine-1-kvm-0"))
   147  	s.assertInstances(c, kvm)
   148  }
   149  
   150  func (s *kvmBrokerSuite) TestStartInstanceAddressAllocationDisabled(c *gc.C) {
   151  	machineId := "1/kvm/0"
   152  	kvm := s.startInstance(c, machineId)
   153  	s.api.CheckCalls(c, []gitjujutesting.StubCall{{
   154  		FuncName: "ContainerConfig",
   155  	}})
   156  	c.Assert(kvm.Id(), gc.Equals, instance.Id("juju-machine-1-kvm-0"))
   157  	s.assertInstances(c, kvm)
   158  }
   159  
   160  func (s *kvmBrokerSuite) TestMaintainInstance(c *gc.C) {
   161  	machineId := "1/kvm/0"
   162  	s.SetFeatureFlags(feature.AddressAllocation)
   163  	kvm := s.startInstance(c, machineId)
   164  	s.api.ResetCalls()
   165  
   166  	s.maintainInstance(c, machineId)
   167  	s.api.CheckCalls(c, []gitjujutesting.StubCall{{
   168  		FuncName: "GetContainerInterfaceInfo",
   169  		Args:     []interface{}{names.NewMachineTag("1-kvm-0")},
   170  	}})
   171  	c.Assert(kvm.Id(), gc.Equals, instance.Id("juju-machine-1-kvm-0"))
   172  	s.assertInstances(c, kvm)
   173  }
   174  
   175  func (s *kvmBrokerSuite) TestMaintainInstanceAddressAllocationDisabled(c *gc.C) {
   176  	machineId := "1/kvm/0"
   177  	kvm := s.startInstance(c, machineId)
   178  	s.api.ResetCalls()
   179  
   180  	s.maintainInstance(c, machineId)
   181  	s.api.CheckCalls(c, []gitjujutesting.StubCall{})
   182  	c.Assert(kvm.Id(), gc.Equals, instance.Id("juju-machine-1-kvm-0"))
   183  	s.assertInstances(c, kvm)
   184  }
   185  
   186  func (s *kvmBrokerSuite) TestStopInstance(c *gc.C) {
   187  	kvm0 := s.startInstance(c, "1/kvm/0")
   188  	kvm1 := s.startInstance(c, "1/kvm/1")
   189  	kvm2 := s.startInstance(c, "1/kvm/2")
   190  
   191  	err := s.broker.StopInstances(kvm0.Id())
   192  	c.Assert(err, jc.ErrorIsNil)
   193  	s.assertInstances(c, kvm1, kvm2)
   194  	c.Assert(s.kvmContainerDir(kvm0), jc.DoesNotExist)
   195  	c.Assert(s.kvmRemovedContainerDir(kvm0), jc.IsDirectory)
   196  
   197  	err = s.broker.StopInstances(kvm1.Id(), kvm2.Id())
   198  	c.Assert(err, jc.ErrorIsNil)
   199  	s.assertInstances(c)
   200  }
   201  
   202  func (s *kvmBrokerSuite) TestAllInstances(c *gc.C) {
   203  	kvm0 := s.startInstance(c, "1/kvm/0")
   204  	kvm1 := s.startInstance(c, "1/kvm/1")
   205  	s.assertInstances(c, kvm0, kvm1)
   206  
   207  	err := s.broker.StopInstances(kvm1.Id())
   208  	c.Assert(err, jc.ErrorIsNil)
   209  	kvm2 := s.startInstance(c, "1/kvm/2")
   210  	s.assertInstances(c, kvm0, kvm2)
   211  }
   212  
   213  func (s *kvmBrokerSuite) assertInstances(c *gc.C, inst ...instance.Instance) {
   214  	results, err := s.broker.AllInstances()
   215  	c.Assert(err, jc.ErrorIsNil)
   216  	instancetest.MatchInstances(c, results, inst...)
   217  }
   218  
   219  func (s *kvmBrokerSuite) kvmContainerDir(inst instance.Instance) string {
   220  	return filepath.Join(s.ContainerDir, string(inst.Id()))
   221  }
   222  
   223  func (s *kvmBrokerSuite) kvmRemovedContainerDir(inst instance.Instance) string {
   224  	return filepath.Join(s.RemovedDir, string(inst.Id()))
   225  }
   226  
   227  type kvmProvisionerSuite struct {
   228  	CommonProvisionerSuite
   229  	kvmSuite
   230  	events chan mock.Event
   231  }
   232  
   233  var _ = gc.Suite(&kvmProvisionerSuite{})
   234  
   235  func (s *kvmProvisionerSuite) SetUpSuite(c *gc.C) {
   236  	if runtime.GOOS == "windows" {
   237  		c.Skip("Skipping kvm tests on windows")
   238  	}
   239  	s.CommonProvisionerSuite.SetUpSuite(c)
   240  	s.kvmSuite.SetUpSuite(c)
   241  }
   242  
   243  func (s *kvmProvisionerSuite) TearDownSuite(c *gc.C) {
   244  	s.kvmSuite.TearDownSuite(c)
   245  	s.CommonProvisionerSuite.TearDownSuite(c)
   246  }
   247  
   248  func (s *kvmProvisionerSuite) SetUpTest(c *gc.C) {
   249  	s.CommonProvisionerSuite.SetUpTest(c)
   250  	s.kvmSuite.SetUpTest(c)
   251  
   252  	s.events = make(chan mock.Event, 25)
   253  	s.ContainerFactory.AddListener(s.events)
   254  }
   255  
   256  func (s *kvmProvisionerSuite) nextEvent(c *gc.C) mock.Event {
   257  	select {
   258  	case event := <-s.events:
   259  		return event
   260  	case <-time.After(coretesting.LongWait):
   261  		c.Fatalf("no event arrived")
   262  	}
   263  	panic("not reachable")
   264  }
   265  
   266  func (s *kvmProvisionerSuite) expectStarted(c *gc.C, machine *state.Machine) string {
   267  	// This check in particular leads to tests just hanging
   268  	// indefinitely quite often on i386.
   269  	coretesting.SkipIfI386(c, "lp:1425569")
   270  
   271  	s.State.StartSync()
   272  	event := s.nextEvent(c)
   273  	c.Assert(event.Action, gc.Equals, mock.Started)
   274  	err := machine.Refresh()
   275  	c.Assert(err, jc.ErrorIsNil)
   276  	s.waitInstanceId(c, machine, instance.Id(event.InstanceId))
   277  	return event.InstanceId
   278  }
   279  
   280  func (s *kvmProvisionerSuite) expectStopped(c *gc.C, instId string) {
   281  	// This check in particular leads to tests just hanging
   282  	// indefinitely quite often on i386.
   283  	coretesting.SkipIfI386(c, "lp:1425569")
   284  
   285  	s.State.StartSync()
   286  	event := s.nextEvent(c)
   287  	c.Assert(event.Action, gc.Equals, mock.Stopped)
   288  	c.Assert(event.InstanceId, gc.Equals, instId)
   289  }
   290  
   291  func (s *kvmProvisionerSuite) expectNoEvents(c *gc.C) {
   292  	select {
   293  	case event := <-s.events:
   294  		c.Fatalf("unexpected event %#v", event)
   295  	case <-time.After(coretesting.ShortWait):
   296  		return
   297  	}
   298  }
   299  
   300  func (s *kvmProvisionerSuite) TearDownTest(c *gc.C) {
   301  	close(s.events)
   302  	s.kvmSuite.TearDownTest(c)
   303  	s.CommonProvisionerSuite.TearDownTest(c)
   304  }
   305  
   306  func (s *kvmProvisionerSuite) newKvmProvisioner(c *gc.C) provisioner.Provisioner {
   307  	machineTag := names.NewMachineTag("0")
   308  	agentConfig := s.AgentConfigForTag(c, machineTag)
   309  	managerConfig := container.ManagerConfig{container.ConfigName: "juju"}
   310  	broker, err := provisioner.NewKvmBroker(s.provisioner, agentConfig, managerConfig, false)
   311  	c.Assert(err, jc.ErrorIsNil)
   312  	toolsFinder := (*provisioner.GetToolsFinder)(s.provisioner)
   313  	return provisioner.NewContainerProvisioner(instance.KVM, s.provisioner, agentConfig, broker, toolsFinder)
   314  }
   315  
   316  func (s *kvmProvisionerSuite) TestProvisionerStartStop(c *gc.C) {
   317  	p := s.newKvmProvisioner(c)
   318  	c.Assert(p.Stop(), gc.IsNil)
   319  }
   320  
   321  func (s *kvmProvisionerSuite) TestDoesNotStartEnvironMachines(c *gc.C) {
   322  	p := s.newKvmProvisioner(c)
   323  	defer stop(c, p)
   324  
   325  	// Check that an instance is not provisioned when the machine is created.
   326  	_, err := s.State.AddMachine(coretesting.FakeDefaultSeries, state.JobHostUnits)
   327  	c.Assert(err, jc.ErrorIsNil)
   328  
   329  	s.expectNoEvents(c)
   330  }
   331  
   332  func (s *kvmProvisionerSuite) TestDoesNotHaveRetryWatcher(c *gc.C) {
   333  	p := s.newKvmProvisioner(c)
   334  	defer stop(c, p)
   335  
   336  	w, err := provisioner.GetRetryWatcher(p)
   337  	c.Assert(w, gc.IsNil)
   338  	c.Assert(err, jc.Satisfies, errors.IsNotImplemented)
   339  }
   340  
   341  func (s *kvmProvisionerSuite) addContainer(c *gc.C) *state.Machine {
   342  	template := state.MachineTemplate{
   343  		Series: coretesting.FakeDefaultSeries,
   344  		Jobs:   []state.MachineJob{state.JobHostUnits},
   345  	}
   346  	container, err := s.State.AddMachineInsideMachine(template, "0", instance.KVM)
   347  	c.Assert(err, jc.ErrorIsNil)
   348  	return container
   349  }
   350  
   351  func (s *kvmProvisionerSuite) TestContainerStartedAndStopped(c *gc.C) {
   352  	coretesting.SkipIfI386(c, "lp:1425569")
   353  
   354  	p := s.newKvmProvisioner(c)
   355  	defer stop(c, p)
   356  
   357  	container := s.addContainer(c)
   358  
   359  	instId := s.expectStarted(c, container)
   360  
   361  	// ...and removed, along with the machine, when the machine is Dead.
   362  	c.Assert(container.EnsureDead(), gc.IsNil)
   363  	s.expectStopped(c, instId)
   364  	s.waitRemoved(c, container)
   365  }
   366  
   367  func (s *kvmProvisionerSuite) TestKVMProvisionerObservesConfigChanges(c *gc.C) {
   368  	p := s.newKvmProvisioner(c)
   369  	defer stop(c, p)
   370  	s.assertProvisionerObservesConfigChanges(c, p)
   371  }