github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/container/kvm/wrappedcmds_test.go (about) 1 // Copyright 2014-2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package kvm_test 5 6 import ( 7 "errors" 8 "os" 9 "path/filepath" 10 11 "github.com/juju/testing" 12 jc "github.com/juju/testing/checkers" 13 gc "gopkg.in/check.v1" 14 15 . "github.com/juju/juju/container/kvm" 16 "github.com/juju/juju/core/paths" 17 "github.com/juju/juju/environs/imagedownloads" 18 "github.com/juju/juju/environs/simplestreams" 19 sstesting "github.com/juju/juju/environs/simplestreams/testing" 20 coretesting "github.com/juju/juju/testing" 21 ) 22 23 type LibVertSuite struct { 24 coretesting.BaseSuite 25 ContainerDir string 26 RemovedDir string 27 } 28 29 var _ = gc.Suite(&LibVertSuite{}) 30 31 func (s *LibVertSuite) SetUpTest(c *gc.C) { 32 s.BaseSuite.SetUpTest(c) 33 } 34 35 type testSyncParams struct { 36 arch, series string 37 srcFunc func() simplestreams.DataSource 38 onevalErr error 39 success bool 40 } 41 42 func (p testSyncParams) One() (*imagedownloads.Metadata, error) { 43 if p.success { 44 return &imagedownloads.Metadata{ 45 Arch: p.arch, 46 Release: p.series, 47 }, nil 48 } 49 return nil, p.onevalErr 50 } 51 52 func (p testSyncParams) sourceURL() (string, error) { 53 return p.srcFunc().URL("") 54 } 55 56 // Test that the call to SyncImages utilizes the defined source 57 func (s *LibVertSuite) TestSyncImagesUtilizesSimpleStreamsSource(c *gc.C) { 58 59 const ( 60 series = "mocked-series" 61 arch = "mocked-arch" 62 source = "mocked-url" 63 ) 64 p := testSyncParams{ 65 arch: arch, 66 series: series, 67 srcFunc: func() simplestreams.DataSource { 68 ss := simplestreams.NewSimpleStreams(sstesting.TestDataSourceFactory()) 69 return imagedownloads.NewDataSource(ss, source) 70 }, 71 success: true, 72 } 73 err := Sync(p, fakeFetcher{}, source, nil) 74 c.Assert(err, jc.ErrorIsNil) 75 76 url, err := p.sourceURL() 77 c.Check(err, jc.ErrorIsNil) 78 c.Check(url, jc.DeepEquals, source+"/") 79 80 res, err := p.One() 81 c.Check(err, jc.ErrorIsNil) 82 83 c.Check(res.Arch, jc.DeepEquals, arch) 84 c.Check(res.Release, jc.DeepEquals, series) 85 } 86 87 // gocheck boilerplate. 88 type commandWrapperSuite struct { 89 testing.IsolationSuite 90 } 91 92 var _ = gc.Suite(&commandWrapperSuite{}) 93 94 func (commandWrapperSuite) TestCreateNoHostname(c *gc.C) { 95 stub := NewRunStub("exit before this", nil) 96 p := CreateMachineParams{} 97 err := CreateMachine(p) 98 c.Assert(len(stub.Calls()) == 0, jc.IsTrue) 99 c.Assert(err, gc.ErrorMatches, "hostname is required") 100 } 101 102 func (s *commandWrapperSuite) TestCreateMachineSuccessOnFocal(c *gc.C) { 103 tmpDir, err := os.MkdirTemp("", "juju-libvirtSuite-") 104 c.Check(err, jc.ErrorIsNil) 105 106 want := []string{ 107 tmpDir + ` genisoimage -output \/tmp\/juju-libvirtSuite-\d+\/kvm\/guests\/host00-ds\.iso -volid cidata -joliet -rock user-data meta-data network-config`, 108 // On focal, the backing image format must be explicitly specified 109 // hence the '-F raw' 110 ` qemu-img create -b \/tmp/juju-libvirtSuite-\d+\/kvm\/guests\/20.04-arm64-backing-file.qcow -F raw -f qcow2 \/tmp\/juju-libvirtSuite-\d+\/kvm\/guests\/host00.qcow 8G`, 111 ` virsh define \/tmp\/juju-libvirtSuite-\d+\/host00.xml`, 112 " virsh start host00", 113 } 114 115 assertCreateMachineSuccess(c, tmpDir, want) 116 } 117 func assertCreateMachineSuccess(c *gc.C, tmpDir string, expCommands []string) { 118 stub := NewRunStub("success", nil) 119 120 err := os.MkdirAll(filepath.Join(tmpDir, "kvm", "guests"), 0755) 121 c.Check(err, jc.ErrorIsNil) 122 cloudInitPath := filepath.Join(tmpDir, "cloud-init") 123 userDataPath := filepath.Join(tmpDir, "user-data") 124 networkConfigPath := filepath.Join(tmpDir, "network-config") 125 err = os.WriteFile(cloudInitPath, []byte("#cloud-init\nEOF\n"), 0755) 126 c.Assert(err, jc.ErrorIsNil) 127 128 defer func() { 129 err := os.RemoveAll(tmpDir) 130 if err != nil { 131 c.Errorf("failed removing %q in test %s", tmpDir, err) 132 } 133 }() 134 pathfinder := func(_ paths.OS) string { 135 return tmpDir 136 } 137 138 hostname := "host00" 139 params := CreateMachineParams{ 140 Hostname: hostname, 141 Version: "20.04", 142 UserDataFile: cloudInitPath, 143 NetworkConfigData: "this-is-network-config", 144 CpuCores: 1, 145 RootDisk: 8, 146 } 147 148 MakeCreateMachineParamsTestable(¶ms, pathfinder, stub.Run, "arm64") 149 err = CreateMachine(params) 150 c.Assert(err, jc.ErrorIsNil) 151 152 _, err = os.Stat(cloudInitPath) 153 c.Assert(os.IsNotExist(err), jc.IsTrue) 154 155 b, err := os.ReadFile(userDataPath) 156 c.Assert(err, jc.ErrorIsNil) 157 c.Assert(string(b), jc.Contains, "#cloud-init") 158 159 b, err = os.ReadFile(networkConfigPath) 160 c.Assert(err, jc.ErrorIsNil) 161 c.Assert(string(b), gc.Equals, "this-is-network-config") 162 163 c.Check(len(stub.Calls()), gc.Equals, len(expCommands)) 164 for i, cmd := range stub.Calls() { 165 c.Check(cmd, gc.Matches, expCommands[i]) 166 } 167 } 168 169 func (commandWrapperSuite) TestDestroyMachineSuccess(c *gc.C) { 170 tmpDir, err := os.MkdirTemp("", "juju-libvirtSuite-") 171 c.Check(err, jc.ErrorIsNil) 172 guestBase := filepath.Join(tmpDir, "kvm", "guests") 173 err = os.MkdirAll(guestBase, 0700) 174 c.Check(err, jc.ErrorIsNil) 175 176 err = os.WriteFile(filepath.Join(guestBase, "aname.qcow"), []byte("diskcontents"), 0700) 177 c.Check(err, jc.ErrorIsNil) 178 err = os.WriteFile(filepath.Join(guestBase, "aname-ds.iso"), []byte("diskcontents"), 0700) 179 c.Check(err, jc.ErrorIsNil) 180 181 pathfinder := func(_ paths.OS) string { 182 return tmpDir 183 } 184 185 stub := NewRunStub("success", nil) 186 container := NewTestContainer("aname", stub.Run, pathfinder) 187 err = DestroyMachine(container) 188 c.Assert(err, jc.ErrorIsNil) 189 c.Assert(stub.Calls(), jc.DeepEquals, []string{ 190 " virsh destroy aname", 191 " virsh undefine --nvram aname", 192 }) 193 } 194 195 func (commandWrapperSuite) TestDestroyMachineFails(c *gc.C) { 196 stub := NewRunStub("", errors.New("Boom")) 197 container := NewTestContainer("aname", stub.Run, nil) 198 err := DestroyMachine(container) 199 c.Check(stub.Calls(), jc.DeepEquals, []string{ 200 " virsh destroy aname", 201 " virsh undefine --nvram aname", 202 }) 203 log := c.GetTestLog() 204 c.Check(log, jc.Contains, "`virsh destroy aname` failed") 205 c.Check(log, jc.Contains, "`virsh undefine --nvram aname` failed") 206 c.Assert(err, jc.ErrorIsNil) 207 208 } 209 210 func (commandWrapperSuite) TestAutostartMachineSuccess(c *gc.C) { 211 stub := NewRunStub("success", nil) 212 container := NewTestContainer("aname", stub.Run, nil) 213 err := AutostartMachine(container) 214 c.Assert(stub.Calls(), jc.DeepEquals, []string{" virsh autostart aname"}) 215 c.Assert(err, jc.ErrorIsNil) 216 } 217 218 func (commandWrapperSuite) TestAutostartMachineFails(c *gc.C) { 219 stub := NewRunStub("", errors.New("Boom")) 220 container := NewTestContainer("aname", stub.Run, nil) 221 err := AutostartMachine(container) 222 c.Assert(stub.Calls(), jc.DeepEquals, []string{" virsh autostart aname"}) 223 c.Check(err, gc.ErrorMatches, `failed to autostart domain "aname": Boom`) 224 } 225 226 func (commandWrapperSuite) TestListMachinesSuccess(c *gc.C) { 227 output := ` 228 Id Name State 229 ---------------------------------------------------- 230 0 Domain-0 running 231 2 ubuntu paused 232 `[1:] 233 stub := NewRunStub(output, nil) 234 got, err := ListMachines(stub.Run) 235 236 c.Check(err, jc.ErrorIsNil) 237 c.Check(stub.Calls(), jc.DeepEquals, []string{" virsh -q list --all"}) 238 c.Assert(got, jc.DeepEquals, map[string]string{ 239 "Domain-0": "running", 240 "ubuntu": "paused", 241 }) 242 243 } 244 245 func (commandWrapperSuite) TestListMachinesFails(c *gc.C) { 246 stub := NewRunStub("", errors.New("Boom")) 247 got, err := ListMachines(stub.Run) 248 c.Check(err, gc.ErrorMatches, "Boom") 249 c.Check(stub.Calls(), jc.DeepEquals, []string{" virsh -q list --all"}) 250 c.Assert(got, gc.IsNil) 251 }