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