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