github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/container/broker/kvm-broker_test.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package broker_test
     5  
     6  import (
     7  	"fmt"
     8  	"path/filepath"
     9  
    10  	"github.com/juju/errors"
    11  	"github.com/juju/names/v5"
    12  	gitjujutesting "github.com/juju/testing"
    13  	jc "github.com/juju/testing/checkers"
    14  	gc "gopkg.in/check.v1"
    15  
    16  	"github.com/juju/juju/agent"
    17  	"github.com/juju/juju/cloudconfig"
    18  	"github.com/juju/juju/cloudconfig/instancecfg"
    19  	"github.com/juju/juju/container"
    20  	"github.com/juju/juju/container/broker"
    21  	"github.com/juju/juju/container/kvm"
    22  	"github.com/juju/juju/container/kvm/mock"
    23  	kvmtesting "github.com/juju/juju/container/kvm/testing"
    24  	corebase "github.com/juju/juju/core/base"
    25  	"github.com/juju/juju/core/instance"
    26  	"github.com/juju/juju/environs"
    27  	"github.com/juju/juju/environs/context"
    28  	coretesting "github.com/juju/juju/testing"
    29  	jujuversion "github.com/juju/juju/version"
    30  )
    31  
    32  type kvmSuite struct {
    33  	kvmtesting.TestSuite
    34  	events     chan mock.Event
    35  	eventsDone chan struct{}
    36  }
    37  
    38  type kvmBrokerSuite struct {
    39  	kvmSuite
    40  	agentConfig agent.Config
    41  	api         *fakeAPI
    42  	manager     *fakeContainerManager
    43  }
    44  
    45  var _ = gc.Suite(&kvmBrokerSuite{})
    46  
    47  func (s *kvmSuite) SetUpTest(c *gc.C) {
    48  	s.TestSuite.SetUpTest(c)
    49  	s.events = make(chan mock.Event)
    50  	s.eventsDone = make(chan struct{})
    51  	go func() {
    52  		defer close(s.eventsDone)
    53  		for event := range s.events {
    54  			c.Output(3, fmt.Sprintf("kvm event: <%s, %s>", event.Action, event.InstanceId))
    55  		}
    56  	}()
    57  	s.TestSuite.ContainerFactory.AddListener(s.events)
    58  }
    59  
    60  func (s *kvmSuite) TearDownTest(c *gc.C) {
    61  	close(s.events)
    62  	<-s.eventsDone
    63  	s.TestSuite.TearDownTest(c)
    64  }
    65  
    66  func (s *kvmBrokerSuite) SetUpTest(c *gc.C) {
    67  	s.kvmSuite.SetUpTest(c)
    68  	broker.PatchNewMachineInitReader(s, newBlankMachineInitReader)
    69  
    70  	var err error
    71  	s.agentConfig, err = agent.NewAgentConfig(
    72  		agent.AgentConfigParams{
    73  			Paths:             agent.NewPathsWithDefaults(agent.Paths{DataDir: "/not/used/here"}),
    74  			Tag:               names.NewUnitTag("ubuntu/1"),
    75  			UpgradedToVersion: jujuversion.Current,
    76  			Password:          "dummy-secret",
    77  			Nonce:             "nonce",
    78  			APIAddresses:      []string{"10.0.0.1:1234"},
    79  			CACert:            coretesting.CACert,
    80  			Controller:        coretesting.ControllerTag,
    81  			Model:             coretesting.ModelTag,
    82  		})
    83  	c.Assert(err, jc.ErrorIsNil)
    84  	s.api = NewFakeAPI()
    85  	s.manager = &fakeContainerManager{}
    86  }
    87  
    88  func (s *kvmBrokerSuite) startInstance(c *gc.C, broker environs.InstanceBroker, machineId string) (*environs.StartInstanceResult, error) {
    89  	return callStartInstance(c, s, broker, machineId)
    90  }
    91  
    92  func (s *kvmBrokerSuite) newKVMBroker(c *gc.C) (environs.InstanceBroker, error) {
    93  	managerConfig := container.ManagerConfig{container.ConfigModelUUID: coretesting.ModelTag.Id()}
    94  	manager, err := kvm.NewContainerManager(managerConfig)
    95  	c.Assert(err, jc.ErrorIsNil)
    96  	return broker.NewKVMBroker(s.api.PrepareHost, s.api, manager, s.agentConfig)
    97  }
    98  
    99  func (s *kvmBrokerSuite) newKVMBrokerFakeManager(c *gc.C) (environs.InstanceBroker, error) {
   100  	return broker.NewKVMBroker(s.api.PrepareHost, s.api, s.manager, s.agentConfig)
   101  }
   102  
   103  func (s *kvmBrokerSuite) TestStartInstanceWithoutNetworkChanges(c *gc.C) {
   104  	broker, brokerErr := s.newKVMBroker(c)
   105  	c.Assert(brokerErr, jc.ErrorIsNil)
   106  
   107  	machineId := "1/kvm/0"
   108  	result, err := s.startInstance(c, broker, machineId)
   109  	c.Assert(err, jc.ErrorIsNil)
   110  	s.api.CheckCalls(c, []gitjujutesting.StubCall{{
   111  		FuncName: "ContainerConfig",
   112  	}, {
   113  		FuncName: "PrepareHost",
   114  		Args:     []interface{}{names.NewMachineTag("1-kvm-0")},
   115  	}, {
   116  		FuncName: "PrepareContainerInterfaceInfo",
   117  		Args:     []interface{}{names.NewMachineTag("1-kvm-0")},
   118  	}})
   119  	c.Assert(result.Instance.Id(), gc.Equals, instance.Id("juju-06f00d-1-kvm-0"))
   120  	s.assertResults(c, broker, result)
   121  }
   122  
   123  func (s *kvmBrokerSuite) TestMaintainInstanceAddress(c *gc.C) {
   124  	broker, brokerErr := s.newKVMBroker(c)
   125  	c.Assert(brokerErr, jc.ErrorIsNil)
   126  
   127  	machineId := "1/kvm/0"
   128  	result, err := s.startInstance(c, broker, machineId)
   129  	c.Assert(err, jc.ErrorIsNil)
   130  
   131  	s.api.ResetCalls()
   132  
   133  	s.api.CheckCalls(c, []gitjujutesting.StubCall{})
   134  	c.Assert(result.Instance.Id(), gc.Equals, instance.Id("juju-06f00d-1-kvm-0"))
   135  	s.assertResults(c, broker, result)
   136  }
   137  
   138  func (s *kvmBrokerSuite) TestStopInstance(c *gc.C) {
   139  	broker, brokerErr := s.newKVMBroker(c)
   140  	c.Assert(brokerErr, jc.ErrorIsNil)
   141  
   142  	result0, err0 := s.startInstance(c, broker, "1/kvm/0")
   143  	c.Assert(err0, jc.ErrorIsNil)
   144  
   145  	result1, err1 := s.startInstance(c, broker, "1/kvm/1")
   146  	c.Assert(err1, jc.ErrorIsNil)
   147  
   148  	result2, err2 := s.startInstance(c, broker, "1/kvm/2")
   149  	c.Assert(err2, jc.ErrorIsNil)
   150  
   151  	callCtx := context.NewEmptyCloudCallContext()
   152  	err := broker.StopInstances(callCtx, result0.Instance.Id())
   153  	c.Assert(err, jc.ErrorIsNil)
   154  	s.assertResults(c, broker, result1, result2)
   155  	c.Assert(s.kvmContainerDir(result0), jc.DoesNotExist)
   156  	c.Assert(s.kvmRemovedContainerDir(result0), jc.IsDirectory)
   157  
   158  	err = broker.StopInstances(callCtx, result1.Instance.Id(), result2.Instance.Id())
   159  	c.Assert(err, jc.ErrorIsNil)
   160  	s.assertNoResults(c, broker)
   161  }
   162  
   163  func (s *kvmBrokerSuite) TestAllRunningInstances(c *gc.C) {
   164  	broker, brokerErr := s.newKVMBroker(c)
   165  	c.Assert(brokerErr, jc.ErrorIsNil)
   166  
   167  	result0, err0 := s.startInstance(c, broker, "1/kvm/0")
   168  	c.Assert(err0, jc.ErrorIsNil)
   169  
   170  	result1, err1 := s.startInstance(c, broker, "1/kvm/1")
   171  	c.Assert(err1, jc.ErrorIsNil)
   172  	s.assertResults(c, broker, result0, result1)
   173  
   174  	err := broker.StopInstances(context.NewEmptyCloudCallContext(), result1.Instance.Id())
   175  	c.Assert(err, jc.ErrorIsNil)
   176  	result2, err2 := s.startInstance(c, broker, "1/kvm/2")
   177  	c.Assert(err2, jc.ErrorIsNil)
   178  	s.assertResults(c, broker, result0, result2)
   179  }
   180  
   181  func (s *kvmBrokerSuite) assertResults(c *gc.C, broker environs.InstanceBroker, results ...*environs.StartInstanceResult) {
   182  	assertInstancesStarted(c, broker, results...)
   183  }
   184  
   185  func (s *kvmBrokerSuite) assertNoResults(c *gc.C, broker environs.InstanceBroker) {
   186  	s.assertResults(c, broker)
   187  }
   188  
   189  func (s *kvmBrokerSuite) kvmContainerDir(result *environs.StartInstanceResult) string {
   190  	inst := result.Instance
   191  	return filepath.Join(s.ContainerDir, string(inst.Id()))
   192  }
   193  
   194  func (s *kvmBrokerSuite) kvmRemovedContainerDir(result *environs.StartInstanceResult) string {
   195  	inst := result.Instance
   196  	return filepath.Join(s.RemovedDir, string(inst.Id()))
   197  }
   198  
   199  func (s *kvmBrokerSuite) TestStartInstancePopulatesFallbackNetworkInfo(c *gc.C) {
   200  	broker, brokerErr := s.newKVMBroker(c)
   201  	c.Assert(brokerErr, jc.ErrorIsNil)
   202  
   203  	patchResolvConf(s, c)
   204  
   205  	s.api.SetErrors(
   206  		nil, // ContainerConfig succeeds
   207  		nil, // HostChangesForContainer succeeds
   208  		errors.NotSupportedf("container address allocation"),
   209  	)
   210  	_, err := s.startInstance(c, broker, "1/kvm/2")
   211  	c.Assert(err, gc.ErrorMatches, "container address allocation not supported")
   212  }
   213  
   214  func (s *kvmBrokerSuite) TestStartInstanceWithCloudInitUserData(c *gc.C) {
   215  	broker, brokerErr := s.newKVMBrokerFakeManager(c)
   216  	c.Assert(brokerErr, jc.ErrorIsNil)
   217  
   218  	_, err := s.startInstance(c, broker, "1/kvm/0")
   219  	c.Assert(err, jc.ErrorIsNil)
   220  
   221  	s.manager.CheckCallNames(c, "CreateContainer")
   222  	call := s.manager.Calls()[0]
   223  	c.Assert(call.Args[0], gc.FitsTypeOf, &instancecfg.InstanceConfig{})
   224  	instanceConfig := call.Args[0].(*instancecfg.InstanceConfig)
   225  	assertCloudInitUserData(instanceConfig.CloudInitUserData, map[string]interface{}{
   226  		"packages":        []interface{}{"python-keystoneclient", "python-glanceclient"},
   227  		"preruncmd":       []interface{}{"mkdir /tmp/preruncmd", "mkdir /tmp/preruncmd2"},
   228  		"postruncmd":      []interface{}{"mkdir /tmp/postruncmd", "mkdir /tmp/postruncmd2"},
   229  		"package_upgrade": false,
   230  	}, c)
   231  }
   232  
   233  func (s *kvmBrokerSuite) TestStartInstanceWithContainerInheritProperties(c *gc.C) {
   234  	broker.PatchNewMachineInitReader(s, newFakeMachineInitReader)
   235  	s.api.fakeContainerConfig.ContainerInheritProperties = "ca-certs,apt-security"
   236  
   237  	broker, brokerErr := s.newKVMBrokerFakeManager(c)
   238  	c.Assert(brokerErr, jc.ErrorIsNil)
   239  
   240  	_, err := s.startInstance(c, broker, "1/kvm/0")
   241  	c.Assert(err, jc.ErrorIsNil)
   242  
   243  	s.manager.CheckCallNames(c, "CreateContainer")
   244  	call := s.manager.Calls()[0]
   245  	c.Assert(call.Args[0], gc.FitsTypeOf, &instancecfg.InstanceConfig{})
   246  	instanceConfig := call.Args[0].(*instancecfg.InstanceConfig)
   247  	assertCloudInitUserData(instanceConfig.CloudInitUserData, map[string]interface{}{
   248  		"packages":        []interface{}{"python-keystoneclient", "python-glanceclient"},
   249  		"preruncmd":       []interface{}{"mkdir /tmp/preruncmd", "mkdir /tmp/preruncmd2"},
   250  		"postruncmd":      []interface{}{"mkdir /tmp/postruncmd", "mkdir /tmp/postruncmd2"},
   251  		"package_upgrade": false,
   252  		"apt": map[string]interface{}{
   253  			"security": []interface{}{
   254  				map[interface{}]interface{}{
   255  					"arches": []interface{}{"default"},
   256  					"uri":    "http://archive.ubuntu.com/ubuntu",
   257  				},
   258  			},
   259  		},
   260  		"ca-certs": map[interface{}]interface{}{
   261  			"remove-defaults": true,
   262  			"trusted":         []interface{}{"-----BEGIN CERTIFICATE-----\nYOUR-ORGS-TRUSTED-CA-CERT-HERE\n-----END CERTIFICATE-----\n"},
   263  		},
   264  	}, c)
   265  }
   266  
   267  type blankMachineInitReader struct {
   268  	cloudconfig.InitReader
   269  }
   270  
   271  func (r *blankMachineInitReader) GetInitConfig() (map[string]interface{}, error) {
   272  	return nil, nil
   273  }
   274  
   275  var newBlankMachineInitReader = func(base corebase.Base) (cloudconfig.InitReader, error) {
   276  	r, err := cloudconfig.NewMachineInitReader(base)
   277  	return &blankMachineInitReader{r}, err
   278  }