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