github.com/mattyw/juju@v0.0.0-20140610034352-732aecd63861/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  	"time"
    10  
    11  	"github.com/juju/errors"
    12  	"github.com/juju/names"
    13  	jc "github.com/juju/testing/checkers"
    14  	gc "launchpad.net/gocheck"
    15  
    16  	"github.com/juju/juju/agent"
    17  	"github.com/juju/juju/constraints"
    18  	"github.com/juju/juju/container"
    19  	"github.com/juju/juju/container/kvm/mock"
    20  	kvmtesting "github.com/juju/juju/container/kvm/testing"
    21  	"github.com/juju/juju/environs"
    22  	"github.com/juju/juju/instance"
    23  	instancetest "github.com/juju/juju/instance/testing"
    24  	jujutesting "github.com/juju/juju/juju/testing"
    25  	"github.com/juju/juju/state"
    26  	coretesting "github.com/juju/juju/testing"
    27  	coretools "github.com/juju/juju/tools"
    28  	"github.com/juju/juju/version"
    29  	"github.com/juju/juju/worker/provisioner"
    30  )
    31  
    32  type kvmSuite struct {
    33  	kvmtesting.TestSuite
    34  	events chan mock.Event
    35  }
    36  
    37  type kvmBrokerSuite struct {
    38  	kvmSuite
    39  	broker      environs.InstanceBroker
    40  	agentConfig agent.Config
    41  }
    42  
    43  var _ = gc.Suite(&kvmBrokerSuite{})
    44  
    45  func (s *kvmSuite) SetUpTest(c *gc.C) {
    46  	s.TestSuite.SetUpTest(c)
    47  	s.events = make(chan mock.Event)
    48  	go func() {
    49  		for event := range s.events {
    50  			c.Output(3, fmt.Sprintf("kvm event: <%s, %s>", event.Action, event.InstanceId))
    51  		}
    52  	}()
    53  	s.TestSuite.Factory.AddListener(s.events)
    54  }
    55  
    56  func (s *kvmSuite) TearDownTest(c *gc.C) {
    57  	close(s.events)
    58  	s.TestSuite.TearDownTest(c)
    59  }
    60  
    61  func (s *kvmBrokerSuite) SetUpTest(c *gc.C) {
    62  	s.kvmSuite.SetUpTest(c)
    63  	tools := &coretools.Tools{
    64  		Version: version.MustParseBinary("2.3.4-foo-bar"),
    65  		URL:     "http://tools.testing.invalid/2.3.4-foo-bar.tgz",
    66  	}
    67  	var err error
    68  	s.agentConfig, err = agent.NewAgentConfig(
    69  		agent.AgentConfigParams{
    70  			DataDir:           "/not/used/here",
    71  			Tag:               "tag",
    72  			UpgradedToVersion: version.Current.Number,
    73  			Password:          "dummy-secret",
    74  			Nonce:             "nonce",
    75  			APIAddresses:      []string{"10.0.0.1:1234"},
    76  			CACert:            coretesting.CACert,
    77  		})
    78  	c.Assert(err, gc.IsNil)
    79  	managerConfig := container.ManagerConfig{container.ConfigName: "juju"}
    80  	s.broker, err = provisioner.NewKvmBroker(&fakeAPI{}, tools, s.agentConfig, managerConfig)
    81  	c.Assert(err, gc.IsNil)
    82  }
    83  
    84  func (s *kvmBrokerSuite) startInstance(c *gc.C, machineId string) instance.Instance {
    85  	machineNonce := "fake-nonce"
    86  	stateInfo := jujutesting.FakeStateInfo(machineId)
    87  	apiInfo := jujutesting.FakeAPIInfo(machineId)
    88  	machineConfig := environs.NewMachineConfig(machineId, machineNonce, nil, stateInfo, apiInfo)
    89  	cons := constraints.Value{}
    90  	possibleTools := s.broker.(coretools.HasTools).Tools("precise")
    91  	kvm, _, _, err := s.broker.StartInstance(environs.StartInstanceParams{
    92  		Constraints:   cons,
    93  		Tools:         possibleTools,
    94  		MachineConfig: machineConfig,
    95  	})
    96  	c.Assert(err, gc.IsNil)
    97  	return kvm
    98  }
    99  
   100  func (s *kvmBrokerSuite) TestStopInstance(c *gc.C) {
   101  	kvm0 := s.startInstance(c, "1/kvm/0")
   102  	kvm1 := s.startInstance(c, "1/kvm/1")
   103  	kvm2 := s.startInstance(c, "1/kvm/2")
   104  
   105  	err := s.broker.StopInstances(kvm0.Id())
   106  	c.Assert(err, gc.IsNil)
   107  	s.assertInstances(c, kvm1, kvm2)
   108  	c.Assert(s.kvmContainerDir(kvm0), jc.DoesNotExist)
   109  	c.Assert(s.kvmRemovedContainerDir(kvm0), jc.IsDirectory)
   110  
   111  	err = s.broker.StopInstances(kvm1.Id(), kvm2.Id())
   112  	c.Assert(err, gc.IsNil)
   113  	s.assertInstances(c)
   114  }
   115  
   116  func (s *kvmBrokerSuite) TestAllInstances(c *gc.C) {
   117  	kvm0 := s.startInstance(c, "1/kvm/0")
   118  	kvm1 := s.startInstance(c, "1/kvm/1")
   119  	s.assertInstances(c, kvm0, kvm1)
   120  
   121  	err := s.broker.StopInstances(kvm1.Id())
   122  	c.Assert(err, gc.IsNil)
   123  	kvm2 := s.startInstance(c, "1/kvm/2")
   124  	s.assertInstances(c, kvm0, kvm2)
   125  }
   126  
   127  func (s *kvmBrokerSuite) assertInstances(c *gc.C, inst ...instance.Instance) {
   128  	results, err := s.broker.AllInstances()
   129  	c.Assert(err, gc.IsNil)
   130  	instancetest.MatchInstances(c, results, inst...)
   131  }
   132  
   133  func (s *kvmBrokerSuite) kvmContainerDir(inst instance.Instance) string {
   134  	return filepath.Join(s.ContainerDir, string(inst.Id()))
   135  }
   136  
   137  func (s *kvmBrokerSuite) kvmRemovedContainerDir(inst instance.Instance) string {
   138  	return filepath.Join(s.RemovedDir, string(inst.Id()))
   139  }
   140  
   141  type kvmProvisionerSuite struct {
   142  	CommonProvisionerSuite
   143  	kvmSuite
   144  	machineId string
   145  	events    chan mock.Event
   146  }
   147  
   148  var _ = gc.Suite(&kvmProvisionerSuite{})
   149  
   150  func (s *kvmProvisionerSuite) SetUpSuite(c *gc.C) {
   151  	s.CommonProvisionerSuite.SetUpSuite(c)
   152  	s.kvmSuite.SetUpSuite(c)
   153  }
   154  
   155  func (s *kvmProvisionerSuite) TearDownSuite(c *gc.C) {
   156  	s.kvmSuite.TearDownSuite(c)
   157  	s.CommonProvisionerSuite.TearDownSuite(c)
   158  }
   159  
   160  func (s *kvmProvisionerSuite) SetUpTest(c *gc.C) {
   161  	s.CommonProvisionerSuite.SetUpTest(c)
   162  	s.kvmSuite.SetUpTest(c)
   163  
   164  	// The kvm provisioner actually needs the machine it is being created on
   165  	// to be in state, in order to get the watcher.
   166  	m, err := s.State.AddMachine(coretesting.FakeDefaultSeries, state.JobHostUnits, state.JobManageEnviron)
   167  	c.Assert(err, gc.IsNil)
   168  	err = m.SetAddresses(instance.NewAddress("0.1.2.3", instance.NetworkUnknown))
   169  	c.Assert(err, gc.IsNil)
   170  
   171  	hostPorts := [][]instance.HostPort{{{
   172  		Address: instance.NewAddress("0.1.2.3", instance.NetworkUnknown),
   173  		Port:    1234,
   174  	}}}
   175  	err = s.State.SetAPIHostPorts(hostPorts)
   176  	c.Assert(err, gc.IsNil)
   177  
   178  	s.machineId = m.Id()
   179  	s.APILogin(c, m)
   180  	err = m.SetAgentVersion(version.Current)
   181  	c.Assert(err, gc.IsNil)
   182  
   183  	s.events = make(chan mock.Event, 25)
   184  	s.Factory.AddListener(s.events)
   185  }
   186  
   187  func (s *kvmProvisionerSuite) expectStarted(c *gc.C, machine *state.Machine) string {
   188  	s.State.StartSync()
   189  	event := <-s.events
   190  	c.Assert(event.Action, gc.Equals, mock.Started)
   191  	err := machine.Refresh()
   192  	c.Assert(err, gc.IsNil)
   193  	s.waitInstanceId(c, machine, instance.Id(event.InstanceId))
   194  	return event.InstanceId
   195  }
   196  
   197  func (s *kvmProvisionerSuite) expectStopped(c *gc.C, instId string) {
   198  	s.State.StartSync()
   199  	event := <-s.events
   200  	c.Assert(event.Action, gc.Equals, mock.Stopped)
   201  	c.Assert(event.InstanceId, gc.Equals, instId)
   202  }
   203  
   204  func (s *kvmProvisionerSuite) expectNoEvents(c *gc.C) {
   205  	select {
   206  	case event := <-s.events:
   207  		c.Fatalf("unexpected event %#v", event)
   208  	case <-time.After(coretesting.ShortWait):
   209  		return
   210  	}
   211  }
   212  
   213  func (s *kvmProvisionerSuite) TearDownTest(c *gc.C) {
   214  	close(s.events)
   215  	s.kvmSuite.TearDownTest(c)
   216  	s.CommonProvisionerSuite.TearDownTest(c)
   217  }
   218  
   219  func (s *kvmProvisionerSuite) newKvmProvisioner(c *gc.C) provisioner.Provisioner {
   220  	machineTag := names.MachineTag(s.machineId)
   221  	agentConfig := s.AgentConfigForTag(c, machineTag)
   222  	tools, err := s.provisioner.Tools(agentConfig.Tag())
   223  	c.Assert(err, gc.IsNil)
   224  	managerConfig := container.ManagerConfig{container.ConfigName: "juju"}
   225  	broker, err := provisioner.NewKvmBroker(s.provisioner, tools, agentConfig, managerConfig)
   226  	c.Assert(err, gc.IsNil)
   227  	return provisioner.NewContainerProvisioner(instance.KVM, s.provisioner, agentConfig, broker)
   228  }
   229  
   230  func (s *kvmProvisionerSuite) TestProvisionerStartStop(c *gc.C) {
   231  	p := s.newKvmProvisioner(c)
   232  	c.Assert(p.Stop(), gc.IsNil)
   233  }
   234  
   235  func (s *kvmProvisionerSuite) TestDoesNotStartEnvironMachines(c *gc.C) {
   236  	p := s.newKvmProvisioner(c)
   237  	defer stop(c, p)
   238  
   239  	// Check that an instance is not provisioned when the machine is created.
   240  	_, err := s.State.AddMachine(coretesting.FakeDefaultSeries, state.JobHostUnits)
   241  	c.Assert(err, gc.IsNil)
   242  
   243  	s.expectNoEvents(c)
   244  }
   245  
   246  func (s *kvmProvisionerSuite) TestDoesNotHaveRetryWatcher(c *gc.C) {
   247  	p := s.newKvmProvisioner(c)
   248  	defer stop(c, p)
   249  
   250  	w, err := provisioner.GetRetryWatcher(p)
   251  	c.Assert(w, gc.IsNil)
   252  	c.Assert(err, jc.Satisfies, errors.IsNotImplemented)
   253  }
   254  
   255  func (s *kvmProvisionerSuite) addContainer(c *gc.C) *state.Machine {
   256  	template := state.MachineTemplate{
   257  		Series: coretesting.FakeDefaultSeries,
   258  		Jobs:   []state.MachineJob{state.JobHostUnits},
   259  	}
   260  	container, err := s.State.AddMachineInsideMachine(template, s.machineId, instance.KVM)
   261  	c.Assert(err, gc.IsNil)
   262  	return container
   263  }
   264  
   265  func (s *kvmProvisionerSuite) TestContainerStartedAndStopped(c *gc.C) {
   266  	p := s.newKvmProvisioner(c)
   267  	defer stop(c, p)
   268  
   269  	container := s.addContainer(c)
   270  
   271  	instId := s.expectStarted(c, container)
   272  
   273  	// ...and removed, along with the machine, when the machine is Dead.
   274  	c.Assert(container.EnsureDead(), gc.IsNil)
   275  	s.expectStopped(c, instId)
   276  	s.waitRemoved(c, container)
   277  }