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