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