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(&params, 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  }