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 }