github.com/cloudbase/juju-core@v0.0.0-20140504232958-a7271ac7912f/worker/provisioner/lxc-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  	"io/ioutil"
     9  	"path/filepath"
    10  	"time"
    11  
    12  	gc "launchpad.net/gocheck"
    13  
    14  	"launchpad.net/juju-core/agent"
    15  	"launchpad.net/juju-core/constraints"
    16  	"launchpad.net/juju-core/container/lxc/mock"
    17  	lxctesting "launchpad.net/juju-core/container/lxc/testing"
    18  	"launchpad.net/juju-core/environs"
    19  	"launchpad.net/juju-core/environs/config"
    20  	"launchpad.net/juju-core/instance"
    21  	instancetest "launchpad.net/juju-core/instance/testing"
    22  	jujutesting "launchpad.net/juju-core/juju/testing"
    23  	"launchpad.net/juju-core/names"
    24  	"launchpad.net/juju-core/state"
    25  	"launchpad.net/juju-core/state/api/params"
    26  	coretesting "launchpad.net/juju-core/testing"
    27  	jc "launchpad.net/juju-core/testing/checkers"
    28  	coretools "launchpad.net/juju-core/tools"
    29  	"launchpad.net/juju-core/version"
    30  	"launchpad.net/juju-core/worker/provisioner"
    31  )
    32  
    33  type lxcSuite struct {
    34  	lxctesting.TestSuite
    35  	events chan mock.Event
    36  }
    37  
    38  type lxcBrokerSuite struct {
    39  	lxcSuite
    40  	broker      environs.InstanceBroker
    41  	agentConfig agent.Config
    42  }
    43  
    44  var _ = gc.Suite(&lxcBrokerSuite{})
    45  
    46  func (s *lxcSuite) 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("lxc event: <%s, %s>", event.Action, event.InstanceId))
    52  		}
    53  	}()
    54  	s.TestSuite.Factory.AddListener(s.events)
    55  }
    56  
    57  func (s *lxcSuite) TearDownTest(c *gc.C) {
    58  	close(s.events)
    59  	s.TestSuite.TearDownTest(c)
    60  }
    61  
    62  func (s *lxcBrokerSuite) SetUpTest(c *gc.C) {
    63  	s.lxcSuite.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:            []byte(coretesting.CACert),
    78  		})
    79  	c.Assert(err, gc.IsNil)
    80  	s.broker, err = provisioner.NewLxcBroker(&fakeAPI{}, tools, s.agentConfig)
    81  	c.Assert(err, gc.IsNil)
    82  }
    83  
    84  func (s *lxcBrokerSuite) 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, "", stateInfo, apiInfo)
    89  	cons := constraints.Value{}
    90  	possibleTools := s.broker.(coretools.HasTools).Tools()
    91  	lxc, _, err := s.broker.StartInstance(cons, possibleTools, machineConfig)
    92  	c.Assert(err, gc.IsNil)
    93  	return lxc
    94  }
    95  
    96  func (s *lxcBrokerSuite) TestStartInstance(c *gc.C) {
    97  	machineId := "1/lxc/0"
    98  	lxc := s.startInstance(c, machineId)
    99  	c.Assert(lxc.Id(), gc.Equals, instance.Id("juju-machine-1-lxc-0"))
   100  	c.Assert(s.lxcContainerDir(lxc), jc.IsDirectory)
   101  	s.assertInstances(c, lxc)
   102  	// Uses default network config
   103  	lxcConfContents, err := ioutil.ReadFile(filepath.Join(s.ContainerDir, string(lxc.Id()), "lxc.conf"))
   104  	c.Assert(err, gc.IsNil)
   105  	c.Assert(string(lxcConfContents), jc.Contains, "lxc.network.type = veth")
   106  	c.Assert(string(lxcConfContents), jc.Contains, "lxc.network.link = lxcbr0")
   107  }
   108  
   109  func (s *lxcBrokerSuite) TestStartInstanceWithBridgeEnviron(c *gc.C) {
   110  	s.agentConfig.SetValue(agent.LxcBridge, "br0")
   111  	machineId := "1/lxc/0"
   112  	lxc := s.startInstance(c, machineId)
   113  	c.Assert(lxc.Id(), gc.Equals, instance.Id("juju-machine-1-lxc-0"))
   114  	c.Assert(s.lxcContainerDir(lxc), jc.IsDirectory)
   115  	s.assertInstances(c, lxc)
   116  	// Uses default network config
   117  	lxcConfContents, err := ioutil.ReadFile(filepath.Join(s.ContainerDir, string(lxc.Id()), "lxc.conf"))
   118  	c.Assert(err, gc.IsNil)
   119  	c.Assert(string(lxcConfContents), jc.Contains, "lxc.network.type = veth")
   120  	c.Assert(string(lxcConfContents), jc.Contains, "lxc.network.link = br0")
   121  }
   122  
   123  func (s *lxcBrokerSuite) TestStopInstance(c *gc.C) {
   124  	lxc0 := s.startInstance(c, "1/lxc/0")
   125  	lxc1 := s.startInstance(c, "1/lxc/1")
   126  	lxc2 := s.startInstance(c, "1/lxc/2")
   127  
   128  	err := s.broker.StopInstances([]instance.Instance{lxc0})
   129  	c.Assert(err, gc.IsNil)
   130  	s.assertInstances(c, lxc1, lxc2)
   131  	c.Assert(s.lxcContainerDir(lxc0), jc.DoesNotExist)
   132  	c.Assert(s.lxcRemovedContainerDir(lxc0), jc.IsDirectory)
   133  
   134  	err = s.broker.StopInstances([]instance.Instance{lxc1, lxc2})
   135  	c.Assert(err, gc.IsNil)
   136  	s.assertInstances(c)
   137  }
   138  
   139  func (s *lxcBrokerSuite) TestAllInstances(c *gc.C) {
   140  	lxc0 := s.startInstance(c, "1/lxc/0")
   141  	lxc1 := s.startInstance(c, "1/lxc/1")
   142  	s.assertInstances(c, lxc0, lxc1)
   143  
   144  	err := s.broker.StopInstances([]instance.Instance{lxc1})
   145  	c.Assert(err, gc.IsNil)
   146  	lxc2 := s.startInstance(c, "1/lxc/2")
   147  	s.assertInstances(c, lxc0, lxc2)
   148  }
   149  
   150  func (s *lxcBrokerSuite) assertInstances(c *gc.C, inst ...instance.Instance) {
   151  	results, err := s.broker.AllInstances()
   152  	c.Assert(err, gc.IsNil)
   153  	instancetest.MatchInstances(c, results, inst...)
   154  }
   155  
   156  func (s *lxcBrokerSuite) lxcContainerDir(inst instance.Instance) string {
   157  	return filepath.Join(s.ContainerDir, string(inst.Id()))
   158  }
   159  
   160  func (s *lxcBrokerSuite) lxcRemovedContainerDir(inst instance.Instance) string {
   161  	return filepath.Join(s.RemovedDir, string(inst.Id()))
   162  }
   163  
   164  type lxcProvisionerSuite struct {
   165  	CommonProvisionerSuite
   166  	lxcSuite
   167  	parentMachineId string
   168  	events          chan mock.Event
   169  }
   170  
   171  var _ = gc.Suite(&lxcProvisionerSuite{})
   172  
   173  func (s *lxcProvisionerSuite) SetUpSuite(c *gc.C) {
   174  	s.CommonProvisionerSuite.SetUpSuite(c)
   175  	s.lxcSuite.SetUpSuite(c)
   176  }
   177  
   178  func (s *lxcProvisionerSuite) TearDownSuite(c *gc.C) {
   179  	s.lxcSuite.TearDownSuite(c)
   180  	s.CommonProvisionerSuite.TearDownSuite(c)
   181  }
   182  
   183  func (s *lxcProvisionerSuite) SetUpTest(c *gc.C) {
   184  	s.CommonProvisionerSuite.SetUpTest(c)
   185  	s.lxcSuite.SetUpTest(c)
   186  
   187  	// The lxc provisioner actually needs the machine it is being created on
   188  	// to be in state, in order to get the watcher.
   189  	m, err := s.State.AddMachine(config.DefaultSeries, state.JobHostUnits, state.JobManageEnviron)
   190  	c.Assert(err, gc.IsNil)
   191  	err = m.SetAddresses([]instance.Address{
   192  		instance.NewAddress("0.1.2.3"),
   193  	})
   194  	c.Assert(err, gc.IsNil)
   195  	s.parentMachineId = m.Id()
   196  	s.APILogin(c, m)
   197  	err = m.SetAgentVersion(version.Current)
   198  	c.Assert(err, gc.IsNil)
   199  
   200  	s.events = make(chan mock.Event, 25)
   201  	s.Factory.AddListener(s.events)
   202  }
   203  
   204  func (s *lxcProvisionerSuite) expectStarted(c *gc.C, machine *state.Machine) string {
   205  	s.State.StartSync()
   206  	event := <-s.events
   207  	c.Assert(event.Action, gc.Equals, mock.Started)
   208  	err := machine.Refresh()
   209  	c.Assert(err, gc.IsNil)
   210  	s.waitInstanceId(c, machine, instance.Id(event.InstanceId))
   211  	return event.InstanceId
   212  }
   213  
   214  func (s *lxcProvisionerSuite) expectStopped(c *gc.C, instId string) {
   215  	s.State.StartSync()
   216  	event := <-s.events
   217  	c.Assert(event.Action, gc.Equals, mock.Stopped)
   218  	c.Assert(event.InstanceId, gc.Equals, instId)
   219  }
   220  
   221  func (s *lxcProvisionerSuite) expectNoEvents(c *gc.C) {
   222  	select {
   223  	case event := <-s.events:
   224  		c.Fatalf("unexpected event %#v", event)
   225  	case <-time.After(coretesting.ShortWait):
   226  		return
   227  	}
   228  }
   229  
   230  func (s *lxcProvisionerSuite) TearDownTest(c *gc.C) {
   231  	close(s.events)
   232  	s.lxcSuite.TearDownTest(c)
   233  	s.CommonProvisionerSuite.TearDownTest(c)
   234  }
   235  
   236  func (s *lxcProvisionerSuite) newLxcProvisioner(c *gc.C) provisioner.Provisioner {
   237  	parentMachineTag := names.MachineTag(s.parentMachineId)
   238  	agentConfig := s.AgentConfigForTag(c, parentMachineTag)
   239  	tools, err := s.provisioner.Tools(agentConfig.Tag())
   240  	c.Assert(err, gc.IsNil)
   241  	broker, err := provisioner.NewLxcBroker(s.provisioner, tools, agentConfig)
   242  	c.Assert(err, gc.IsNil)
   243  	return provisioner.NewContainerProvisioner(instance.LXC, s.provisioner, agentConfig, broker)
   244  }
   245  
   246  func (s *lxcProvisionerSuite) TestProvisionerStartStop(c *gc.C) {
   247  	p := s.newLxcProvisioner(c)
   248  	c.Assert(p.Stop(), gc.IsNil)
   249  }
   250  
   251  func (s *lxcProvisionerSuite) TestDoesNotStartEnvironMachines(c *gc.C) {
   252  	p := s.newLxcProvisioner(c)
   253  	defer stop(c, p)
   254  
   255  	// Check that an instance is not provisioned when the machine is created.
   256  	_, err := s.State.AddMachine(config.DefaultSeries, state.JobHostUnits)
   257  	c.Assert(err, gc.IsNil)
   258  
   259  	s.expectNoEvents(c)
   260  }
   261  
   262  func (s *lxcProvisionerSuite) addContainer(c *gc.C) *state.Machine {
   263  	template := state.MachineTemplate{
   264  		Series: config.DefaultSeries,
   265  		Jobs:   []state.MachineJob{state.JobHostUnits},
   266  	}
   267  	container, err := s.State.AddMachineInsideMachine(template, s.parentMachineId, instance.LXC)
   268  	c.Assert(err, gc.IsNil)
   269  	return container
   270  }
   271  
   272  func (s *lxcProvisionerSuite) TestContainerStartedAndStopped(c *gc.C) {
   273  	p := s.newLxcProvisioner(c)
   274  	defer stop(c, p)
   275  
   276  	container := s.addContainer(c)
   277  	instId := s.expectStarted(c, container)
   278  
   279  	// ...and removed, along with the machine, when the machine is Dead.
   280  	c.Assert(container.EnsureDead(), gc.IsNil)
   281  	s.expectStopped(c, instId)
   282  	s.waitRemoved(c, container)
   283  }
   284  
   285  type fakeAPI struct{}
   286  
   287  func (*fakeAPI) ContainerConfig() (params.ContainerConfig, error) {
   288  	return params.ContainerConfig{
   289  		ProviderType:            "fake",
   290  		AuthorizedKeys:          coretesting.FakeAuthKeys,
   291  		SSLHostnameVerification: true}, nil
   292  }