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 }