github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/container/kvm/kvm_test.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package kvm_test
     5  
     6  import (
     7  	"fmt"
     8  	"io/ioutil"
     9  	"path/filepath"
    10  
    11  	"github.com/juju/loggo"
    12  	jc "github.com/juju/testing/checkers"
    13  	"github.com/juju/utils/arch"
    14  	gc "gopkg.in/check.v1"
    15  
    16  	"github.com/juju/juju/container"
    17  	"github.com/juju/juju/container/kvm"
    18  	kvmtesting "github.com/juju/juju/container/kvm/testing"
    19  	containertesting "github.com/juju/juju/container/testing"
    20  	"github.com/juju/juju/core/constraints"
    21  	"github.com/juju/juju/core/instance"
    22  	"github.com/juju/juju/environs/config"
    23  	"github.com/juju/juju/environs/imagemetadata"
    24  	coretesting "github.com/juju/juju/testing"
    25  )
    26  
    27  type KVMSuite struct {
    28  	kvmtesting.TestSuite
    29  	manager container.Manager
    30  }
    31  
    32  var _ = gc.Suite(&KVMSuite{})
    33  
    34  func (s *KVMSuite) SetUpTest(c *gc.C) {
    35  	s.TestSuite.SetUpTest(c)
    36  	var err error
    37  	s.manager, err = kvm.NewContainerManager(container.ManagerConfig{
    38  		container.ConfigModelUUID:      coretesting.ModelTag.Id(),
    39  		config.ContainerImageStreamKey: imagemetadata.ReleasedStream,
    40  	})
    41  	c.Assert(err, jc.ErrorIsNil)
    42  }
    43  
    44  func (*KVMSuite) TestManagerModelUUIDNeeded(c *gc.C) {
    45  	manager, err := kvm.NewContainerManager(container.ManagerConfig{container.ConfigModelUUID: ""})
    46  	c.Assert(err, gc.ErrorMatches, "model UUID is required")
    47  	c.Assert(manager, gc.IsNil)
    48  }
    49  
    50  func (*KVMSuite) TestManagerWarnsAboutUnknownOption(c *gc.C) {
    51  	_, err := kvm.NewContainerManager(container.ManagerConfig{
    52  		container.ConfigModelUUID: coretesting.ModelTag.Id(),
    53  		"shazam":                  "Captain Marvel",
    54  	})
    55  	c.Assert(err, jc.ErrorIsNil)
    56  	c.Assert(c.GetTestLog(), jc.Contains, `INFO juju.container unused config option: "shazam" -> "Captain Marvel"`)
    57  }
    58  
    59  func (s *KVMSuite) TestListInitiallyEmpty(c *gc.C) {
    60  	containers, err := s.manager.ListContainers()
    61  	c.Assert(err, jc.ErrorIsNil)
    62  	c.Assert(containers, gc.HasLen, 0)
    63  }
    64  
    65  func (s *KVMSuite) createRunningContainer(c *gc.C, name string) kvm.Container {
    66  	kvmContainer := s.ContainerFactory.New(name)
    67  	network := container.BridgeNetworkConfig("testbr0", 0, nil)
    68  	c.Assert(kvmContainer.Start(kvm.StartParams{
    69  		Series:       "quantal",
    70  		Arch:         arch.HostArch(),
    71  		UserDataFile: "userdata.txt",
    72  		Network:      network}), gc.IsNil)
    73  	return kvmContainer
    74  }
    75  
    76  func (s *KVMSuite) TestListMatchesManagerName(c *gc.C) {
    77  	s.createRunningContainer(c, "juju-06f00d-match1")
    78  	s.createRunningContainer(c, "juju-06f00d-match2")
    79  	s.createRunningContainer(c, "testNoMatch")
    80  	s.createRunningContainer(c, "other")
    81  	containers, err := s.manager.ListContainers()
    82  	c.Assert(err, jc.ErrorIsNil)
    83  	c.Assert(containers, gc.HasLen, 2)
    84  	expectedIds := []instance.Id{"juju-06f00d-match1", "juju-06f00d-match2"}
    85  	ids := []instance.Id{containers[0].Id(), containers[1].Id()}
    86  	c.Assert(ids, jc.SameContents, expectedIds)
    87  }
    88  
    89  func (s *KVMSuite) TestListMatchesRunningContainers(c *gc.C) {
    90  	running := s.createRunningContainer(c, "juju-06f00d-running")
    91  	s.ContainerFactory.New("juju-06f00d-stopped")
    92  	containers, err := s.manager.ListContainers()
    93  	c.Assert(err, jc.ErrorIsNil)
    94  	c.Assert(containers, gc.HasLen, 1)
    95  	c.Assert(string(containers[0].Id()), gc.Equals, running.Name())
    96  }
    97  
    98  func (s *KVMSuite) TestCreateContainer(c *gc.C) {
    99  	instance := containertesting.CreateContainer(c, s.manager, "1/kvm/0")
   100  	name := string(instance.Id())
   101  	cloudInitFilename := filepath.Join(s.ContainerDir, name, "cloud-init")
   102  	containertesting.AssertCloudInit(c, cloudInitFilename)
   103  }
   104  
   105  func (s *KVMSuite) TestDestroyContainer(c *gc.C) {
   106  	instance := containertesting.CreateContainer(c, s.manager, "1/kvm/0")
   107  
   108  	err := s.manager.DestroyContainer(instance.Id())
   109  	c.Assert(err, jc.ErrorIsNil)
   110  
   111  	name := string(instance.Id())
   112  	// Check that the container dir is no longer in the container dir
   113  	c.Assert(filepath.Join(s.ContainerDir, name), jc.DoesNotExist)
   114  	// but instead, in the removed container dir
   115  	c.Assert(filepath.Join(s.RemovedDir, name), jc.IsDirectory)
   116  }
   117  
   118  // Test that CreateContainer creates proper startParams.
   119  func (s *KVMSuite) TestCreateContainerUtilizesReleaseSimpleStream(c *gc.C) {
   120  
   121  	// Mock machineConfig with a mocked simple stream URL.
   122  	instanceConfig, err := containertesting.MockMachineConfig("1/kvm/0")
   123  	c.Assert(err, jc.ErrorIsNil)
   124  
   125  	// CreateContainer sets TestStartParams internally; we call this
   126  	// purely for the side-effect.
   127  	containertesting.CreateContainerWithMachineConfig(c, s.manager, instanceConfig)
   128  
   129  	c.Assert(kvm.TestStartParams.ImageDownloadURL, gc.Equals, "")
   130  	c.Assert(kvm.TestStartParams.Stream, gc.Equals, "released")
   131  }
   132  
   133  // Test that CreateContainer creates proper startParams.
   134  func (s *KVMSuite) TestCreateContainerUtilizesDailySimpleStream(c *gc.C) {
   135  
   136  	// Mock machineConfig with a mocked simple stream URL.
   137  	instanceConfig, err := containertesting.MockMachineConfig("1/kvm/0")
   138  	c.Assert(err, jc.ErrorIsNil)
   139  
   140  	s.manager, err = kvm.NewContainerManager(container.ManagerConfig{
   141  		container.ConfigModelUUID:      coretesting.ModelTag.Id(),
   142  		config.ContainerImageStreamKey: "daily",
   143  	})
   144  	c.Assert(err, jc.ErrorIsNil)
   145  
   146  	// CreateContainer sets TestStartParams internally;
   147  	// we call this purely for the side-effect.
   148  	containertesting.CreateContainerWithMachineConfig(c, s.manager, instanceConfig)
   149  
   150  	c.Assert(kvm.TestStartParams.ImageDownloadURL, gc.Equals, "http://cloud-images.ubuntu.com/daily")
   151  	c.Assert(kvm.TestStartParams.Stream, gc.Equals, "daily")
   152  }
   153  
   154  func (s *KVMSuite) TestCreateContainerUtilizesSetImageMetadataURL(c *gc.C) {
   155  
   156  	// Mock machineConfig with a mocked simple stream URL.
   157  	instanceConfig, err := containertesting.MockMachineConfig("1/kvm/0")
   158  	c.Assert(err, jc.ErrorIsNil)
   159  
   160  	s.manager, err = kvm.NewContainerManager(container.ManagerConfig{
   161  		container.ConfigModelUUID:           coretesting.ModelTag.Id(),
   162  		config.ContainerImageMetadataURLKey: "https://images.linuxcontainers.org",
   163  	})
   164  	c.Assert(err, jc.ErrorIsNil)
   165  
   166  	// CreateContainer sets TestStartParams internally;
   167  	// we call this purely for the side-effect.
   168  	containertesting.CreateContainerWithMachineConfig(c, s.manager, instanceConfig)
   169  
   170  	c.Assert(kvm.TestStartParams.ImageDownloadURL, gc.Equals, "https://images.linuxcontainers.org")
   171  }
   172  
   173  func (s *KVMSuite) TestStartContainerUtilizesSimpleStream(c *gc.C) {
   174  
   175  	startParams := kvm.StartParams{
   176  		Series:           "mocked-series",
   177  		Arch:             "mocked-arch",
   178  		Stream:           "released",
   179  		ImageDownloadURL: "mocked-url",
   180  	}
   181  	mockedContainer := kvm.NewEmptyKvmContainer()
   182  	mockedContainer.Start(startParams)
   183  
   184  	expectedArgs := fmt.Sprintf(
   185  		"synchronise images for %s %s %s %s",
   186  		startParams.Arch,
   187  		startParams.Series,
   188  		startParams.Stream,
   189  		startParams.ImageDownloadURL,
   190  	)
   191  	c.Assert(c.GetTestLog(), jc.Contains, expectedArgs)
   192  }
   193  
   194  type ConstraintsSuite struct {
   195  	coretesting.BaseSuite
   196  }
   197  
   198  var _ = gc.Suite(&ConstraintsSuite{})
   199  
   200  func (s *ConstraintsSuite) TestDefaults(c *gc.C) {
   201  
   202  	for _, test := range []struct {
   203  		cons     string
   204  		expected kvm.StartParams
   205  		infoLog  []string
   206  	}{{
   207  		expected: kvm.StartParams{
   208  			Memory:   kvm.DefaultMemory,
   209  			CpuCores: kvm.DefaultCpu,
   210  			RootDisk: kvm.DefaultDisk,
   211  		},
   212  	}, {
   213  		cons: "mem=256M",
   214  		expected: kvm.StartParams{
   215  			Memory:   kvm.MinMemory,
   216  			CpuCores: kvm.DefaultCpu,
   217  			RootDisk: kvm.DefaultDisk,
   218  		},
   219  	}, {
   220  		cons: "mem=4G",
   221  		expected: kvm.StartParams{
   222  			Memory:   4 * 1024,
   223  			CpuCores: kvm.DefaultCpu,
   224  			RootDisk: kvm.DefaultDisk,
   225  		},
   226  	}, {
   227  		cons: "cores=4",
   228  		expected: kvm.StartParams{
   229  			Memory:   kvm.DefaultMemory,
   230  			CpuCores: 4,
   231  			RootDisk: kvm.DefaultDisk,
   232  		},
   233  	}, {
   234  		cons: "cores=0",
   235  		expected: kvm.StartParams{
   236  			Memory:   kvm.DefaultMemory,
   237  			CpuCores: kvm.MinCpu,
   238  			RootDisk: kvm.DefaultDisk,
   239  		},
   240  	}, {
   241  		cons: "root-disk=512M",
   242  		expected: kvm.StartParams{
   243  			Memory:   kvm.DefaultMemory,
   244  			CpuCores: kvm.DefaultCpu,
   245  			RootDisk: kvm.MinDisk,
   246  		},
   247  	}, {
   248  		cons: "root-disk=4G",
   249  		expected: kvm.StartParams{
   250  			Memory:   kvm.DefaultMemory,
   251  			CpuCores: kvm.DefaultCpu,
   252  			RootDisk: 4,
   253  		},
   254  	}, {
   255  		cons: "arch=armhf",
   256  		expected: kvm.StartParams{
   257  			Memory:   kvm.DefaultMemory,
   258  			CpuCores: kvm.DefaultCpu,
   259  			RootDisk: kvm.DefaultDisk,
   260  		},
   261  		infoLog: []string{
   262  			`arch constraint of "armhf" being ignored as not supported`,
   263  		},
   264  	}, {
   265  		cons: "container=lxd",
   266  		expected: kvm.StartParams{
   267  			Memory:   kvm.DefaultMemory,
   268  			CpuCores: kvm.DefaultCpu,
   269  			RootDisk: kvm.DefaultDisk,
   270  		},
   271  		infoLog: []string{
   272  			`container constraint of "lxd" being ignored as not supported`,
   273  		},
   274  	}, {
   275  		cons: "cpu-power=100",
   276  		expected: kvm.StartParams{
   277  			Memory:   kvm.DefaultMemory,
   278  			CpuCores: kvm.DefaultCpu,
   279  			RootDisk: kvm.DefaultDisk,
   280  		},
   281  		infoLog: []string{
   282  			`cpu-power constraint of 100 being ignored as not supported`,
   283  		},
   284  	}, {
   285  		cons: "tags=foo,bar",
   286  		expected: kvm.StartParams{
   287  			Memory:   kvm.DefaultMemory,
   288  			CpuCores: kvm.DefaultCpu,
   289  			RootDisk: kvm.DefaultDisk,
   290  		},
   291  		infoLog: []string{
   292  			`tags constraint of "foo,bar" being ignored as not supported`,
   293  		},
   294  	}, {
   295  		cons: "mem=4G cores=4 root-disk=20G arch=armhf cpu-power=100 container=lxd tags=foo,bar",
   296  		expected: kvm.StartParams{
   297  			Memory:   4 * 1024,
   298  			CpuCores: 4,
   299  			RootDisk: 20,
   300  		},
   301  		infoLog: []string{
   302  			`arch constraint of "armhf" being ignored as not supported`,
   303  			`container constraint of "lxd" being ignored as not supported`,
   304  			`cpu-power constraint of 100 being ignored as not supported`,
   305  			`tags constraint of "foo,bar" being ignored as not supported`,
   306  		},
   307  	}} {
   308  		var tw loggo.TestWriter
   309  		c.Assert(loggo.RegisterWriter("constraint-tester", &tw), gc.IsNil)
   310  		cons := constraints.MustParse(test.cons)
   311  		params := kvm.ParseConstraintsToStartParams(cons)
   312  		c.Check(params, gc.DeepEquals, test.expected)
   313  		c.Check(tw.Log(), jc.LogMatches, test.infoLog)
   314  		loggo.RemoveWriter("constraint-tester")
   315  	}
   316  }
   317  
   318  // Test the output when no binary can be found.
   319  func (s *KVMSuite) TestIsKVMSupportedKvmOkNotFound(c *gc.C) {
   320  	// With no path, and no backup directory, we should fail.
   321  	s.PatchEnvironment("PATH", "")
   322  	s.PatchValue(kvm.KVMPath, "")
   323  
   324  	supported, err := kvm.IsKVMSupported()
   325  	c.Check(supported, jc.IsFalse)
   326  	c.Assert(err, gc.ErrorMatches, "kvm-ok executable not found")
   327  }
   328  
   329  // Test the output when the binary is found, but errors out.
   330  func (s *KVMSuite) TestIsKVMSupportedBinaryErrorsOut(c *gc.C) {
   331  	// Clear path so real binary is not found.
   332  	s.PatchEnvironment("PATH", "")
   333  
   334  	// Create mocked binary which returns an error and give the test access.
   335  	tmpDir := c.MkDir()
   336  	err := ioutil.WriteFile(filepath.Join(tmpDir, "kvm-ok"), []byte("#!/bin/bash\nexit 127"), 0777)
   337  	c.Assert(err, jc.ErrorIsNil)
   338  	s.PatchValue(kvm.KVMPath, tmpDir)
   339  
   340  	supported, err := kvm.IsKVMSupported()
   341  	c.Check(supported, jc.IsFalse)
   342  	c.Assert(err, gc.ErrorMatches, "exit status 127")
   343  }
   344  
   345  // Test the case where kvm-ok is not in the path, but is in the
   346  // specified directory.
   347  func (s *KVMSuite) TestIsKVMSupportedNoPath(c *gc.C) {
   348  	// Create a mocked binary so that this test does not fail for
   349  	// developers without kvm-ok.
   350  	s.PatchEnvironment("PATH", "")
   351  	tmpDir := c.MkDir()
   352  	err := ioutil.WriteFile(filepath.Join(tmpDir, "kvm-ok"), []byte("#!/bin/bash"), 0777)
   353  	c.Assert(err, jc.ErrorIsNil)
   354  	s.PatchValue(kvm.KVMPath, tmpDir)
   355  
   356  	supported, err := kvm.IsKVMSupported()
   357  	c.Check(supported, jc.IsTrue)
   358  	c.Assert(err, jc.ErrorIsNil)
   359  }
   360  
   361  // Test the case that kvm-ok is found in the path.
   362  func (s *KVMSuite) TestIsKVMSupportedOnlyPath(c *gc.C) {
   363  	// Create a mocked binary so that this test does not fail for
   364  	// developers without kvm-ok.
   365  	tmpDir := c.MkDir()
   366  	err := ioutil.WriteFile(filepath.Join(tmpDir, "kvm-ok"), []byte("#!/bin/bash"), 0777)
   367  	c.Check(err, jc.ErrorIsNil)
   368  	s.PatchEnvironment("PATH", tmpDir)
   369  
   370  	supported, err := kvm.IsKVMSupported()
   371  	c.Check(supported, jc.IsTrue)
   372  	c.Assert(err, jc.ErrorIsNil)
   373  }
   374  
   375  func (s *KVMSuite) TestKVMPathIsCorrect(c *gc.C) {
   376  	c.Assert(*kvm.KVMPath, gc.Equals, "/usr/sbin")
   377  }