github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/provider/lxd/provider_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package lxd_test 5 6 import ( 7 stdcontext "context" 8 "fmt" 9 "net/http" 10 "net/http/httptest" 11 "path" 12 "strings" 13 14 "github.com/juju/errors" 15 gitjujutesting "github.com/juju/testing" 16 jc "github.com/juju/testing/checkers" 17 "github.com/juju/utils/v3" 18 "go.uber.org/mock/gomock" 19 gc "gopkg.in/check.v1" 20 "gopkg.in/yaml.v2" 21 22 "github.com/juju/juju/cloud" 23 "github.com/juju/juju/environs" 24 environscloudspec "github.com/juju/juju/environs/cloudspec" 25 "github.com/juju/juju/environs/context" 26 "github.com/juju/juju/environs/testing" 27 "github.com/juju/juju/juju/osenv" 28 "github.com/juju/juju/provider/lxd" 29 "github.com/juju/juju/provider/lxd/lxdnames" 30 jujutesting "github.com/juju/juju/testing" 31 ) 32 33 var ( 34 _ = gc.Suite(&providerSuite{}) 35 _ = gc.Suite(&ProviderFunctionalSuite{}) 36 ) 37 38 type providerSuite struct { 39 lxd.BaseSuite 40 } 41 42 func (s *providerSuite) SetUpTest(c *gc.C) { 43 s.BaseSuite.SetUpTest(c) 44 } 45 46 type providerSuiteDeps struct { 47 provider environs.EnvironProvider 48 creds *testing.MockProviderCredentials 49 credsRegister *testing.MockProviderCredentialsRegister 50 factory *lxd.MockServerFactory 51 configReader *lxd.MockLXCConfigReader 52 } 53 54 func (s *providerSuite) createProvider(ctrl *gomock.Controller) providerSuiteDeps { 55 creds := testing.NewMockProviderCredentials(ctrl) 56 credsRegister := testing.NewMockProviderCredentialsRegister(ctrl) 57 factory := lxd.NewMockServerFactory(ctrl) 58 configReader := lxd.NewMockLXCConfigReader(ctrl) 59 60 provider := lxd.NewProviderWithMocks(creds, credsRegister, factory, configReader) 61 return providerSuiteDeps{ 62 provider: provider, 63 creds: creds, 64 credsRegister: credsRegister, 65 factory: factory, 66 configReader: configReader, 67 } 68 } 69 70 func (s *providerSuite) TestDetectClouds(c *gc.C) { 71 ctrl := gomock.NewController(c) 72 defer ctrl.Finish() 73 74 deps := s.createProvider(ctrl) 75 deps.configReader.EXPECT().ReadConfig(path.Join(osenv.JujuXDGDataHomePath("lxd"), "config.yml")).Return(lxd.LXCConfig{}, errors.New("bad")) 76 deps.configReader.EXPECT().ReadConfig(path.Join(utils.Home(), ".config/lxc/config.yml")).Return(lxd.LXCConfig{}, errors.New("bad")) 77 deps.configReader.EXPECT().ReadConfig(path.Join(utils.Home(), "snap/lxd/current/.config/lxc/config.yml")).Return(lxd.LXCConfig{}, nil) 78 deps.configReader.EXPECT().ReadConfig(path.Join(utils.Home(), "snap/lxd/common/config/config.yml")).Return(lxd.LXCConfig{}, errors.New("bad")) 79 80 cloudDetector := deps.provider.(environs.CloudDetector) 81 82 clouds, err := cloudDetector.DetectClouds() 83 c.Assert(err, jc.ErrorIsNil) 84 c.Assert(clouds, gc.HasLen, 1) 85 s.assertLocalhostCloud(c, clouds[0]) 86 } 87 88 func (s *providerSuite) TestRemoteDetectClouds(c *gc.C) { 89 ctrl := gomock.NewController(c) 90 defer ctrl.Finish() 91 92 deps := s.createProvider(ctrl) 93 94 deps.configReader.EXPECT().ReadConfig(path.Join(osenv.JujuXDGDataHomePath("lxd"), "config.yml")).Return(lxd.LXCConfig{}, errors.New("bad")) 95 deps.configReader.EXPECT().ReadConfig(path.Join(utils.Home(), ".config/lxc/config.yml")).Return(lxd.LXCConfig{}, errors.New("bad")) 96 deps.configReader.EXPECT().ReadConfig(path.Join(utils.Home(), "snap/lxd/current/.config/lxc/config.yml")).Return(lxd.LXCConfig{ 97 DefaultRemote: "localhost", 98 Remotes: map[string]lxd.LXCRemoteConfig{ 99 "nuc1": { 100 Addr: "https://10.0.0.1:8443", 101 AuthType: "certificate", 102 Protocol: "lxd", 103 Public: false, 104 }, 105 }, 106 }, nil) 107 deps.configReader.EXPECT().ReadConfig(path.Join(utils.Home(), "snap/lxd/common/config/config.yml")).Return(lxd.LXCConfig{}, errors.New("bad")) 108 109 cloudDetector := deps.provider.(environs.CloudDetector) 110 111 clouds, err := cloudDetector.DetectClouds() 112 c.Assert(err, jc.ErrorIsNil) 113 c.Assert(clouds, gc.HasLen, 2) 114 c.Assert(clouds, jc.DeepEquals, []cloud.Cloud{ 115 { 116 Name: "localhost", 117 Type: "lxd", 118 AuthTypes: []cloud.AuthType{ 119 cloud.CertificateAuthType, 120 }, 121 Regions: []cloud.Region{{ 122 Name: "localhost", 123 }}, 124 Description: "LXD Container Hypervisor", 125 }, 126 { 127 Name: "nuc1", 128 Type: "lxd", 129 Endpoint: "https://10.0.0.1:8443", 130 AuthTypes: []cloud.AuthType{ 131 cloud.CertificateAuthType, 132 }, 133 Regions: []cloud.Region{{ 134 Name: "default", 135 Endpoint: "https://10.0.0.1:8443", 136 }}, 137 Description: "LXD Cluster", 138 }, 139 }) 140 } 141 142 func (s *providerSuite) TestRemoteDetectCloudsWithConfigError(c *gc.C) { 143 ctrl := gomock.NewController(c) 144 defer ctrl.Finish() 145 146 deps := s.createProvider(ctrl) 147 deps.configReader.EXPECT().ReadConfig(path.Join(osenv.JujuXDGDataHomePath("lxd"), "config.yml")).Return(lxd.LXCConfig{}, errors.New("bad")) 148 deps.configReader.EXPECT().ReadConfig(path.Join(utils.Home(), ".config/lxc/config.yml")).Return(lxd.LXCConfig{}, errors.New("bad")) 149 deps.configReader.EXPECT().ReadConfig(path.Join(utils.Home(), "snap/lxd/current/.config/lxc/config.yml")).Return(lxd.LXCConfig{}, errors.New("bad")) 150 deps.configReader.EXPECT().ReadConfig(path.Join(utils.Home(), "snap/lxd/common/config/config.yml")).Return(lxd.LXCConfig{}, errors.New("bad")) 151 152 cloudDetector := deps.provider.(environs.CloudDetector) 153 154 clouds, err := cloudDetector.DetectClouds() 155 c.Assert(err, jc.ErrorIsNil) 156 c.Assert(clouds, gc.HasLen, 1) 157 s.assertLocalhostCloud(c, clouds[0]) 158 } 159 160 func (s *providerSuite) TestDetectCloud(c *gc.C) { 161 ctrl := gomock.NewController(c) 162 defer ctrl.Finish() 163 164 deps := s.createProvider(ctrl) 165 deps.configReader.EXPECT().ReadConfig(path.Join(osenv.JujuXDGDataHomePath("lxd"), "config.yml")).Return(lxd.LXCConfig{}, errors.New("bad")) 166 deps.configReader.EXPECT().ReadConfig(path.Join(utils.Home(), ".config/lxc/config.yml")).Return(lxd.LXCConfig{}, errors.New("bad")) 167 deps.configReader.EXPECT().ReadConfig(path.Join(utils.Home(), "snap/lxd/current/.config/lxc/config.yml")).Return(lxd.LXCConfig{}, errors.New("bad")) 168 deps.configReader.EXPECT().ReadConfig(path.Join(utils.Home(), "snap/lxd/common/config/config.yml")).Return(lxd.LXCConfig{}, errors.New("bad")) 169 deps.configReader.EXPECT().ReadConfig(path.Join(osenv.JujuXDGDataHomePath("lxd"), "config.yml")).Return(lxd.LXCConfig{}, errors.New("bad")) 170 deps.configReader.EXPECT().ReadConfig(path.Join(utils.Home(), ".config/lxc/config.yml")).Return(lxd.LXCConfig{}, errors.New("bad")) 171 deps.configReader.EXPECT().ReadConfig(path.Join(utils.Home(), "snap/lxd/current/.config/lxc/config.yml")).Return(lxd.LXCConfig{}, errors.New("bad")) 172 deps.configReader.EXPECT().ReadConfig(path.Join(utils.Home(), "snap/lxd/common/config/config.yml")).Return(lxd.LXCConfig{}, errors.New("bad")) 173 cloudDetector := deps.provider.(environs.CloudDetector) 174 175 cloud, err := cloudDetector.DetectCloud("localhost") 176 c.Assert(err, jc.ErrorIsNil) 177 s.assertLocalhostCloud(c, cloud) 178 cloud, err = cloudDetector.DetectCloud("lxd") 179 c.Assert(err, jc.ErrorIsNil) 180 s.assertLocalhostCloud(c, cloud) 181 } 182 183 func (s *providerSuite) TestRemoteDetectCloud(c *gc.C) { 184 ctrl := gomock.NewController(c) 185 defer ctrl.Finish() 186 187 deps := s.createProvider(ctrl) 188 cloudDetector := deps.provider.(environs.CloudDetector) 189 190 deps.configReader.EXPECT().ReadConfig(path.Join(osenv.JujuXDGDataHomePath("lxd"), "config.yml")).Return(lxd.LXCConfig{}, errors.New("bad")) 191 deps.configReader.EXPECT().ReadConfig(path.Join(utils.Home(), ".config/lxc/config.yml")).Return(lxd.LXCConfig{}, errors.New("bad")) 192 deps.configReader.EXPECT().ReadConfig(path.Join(utils.Home(), "snap/lxd/common/config/config.yml")).Return(lxd.LXCConfig{}, errors.New("bad")) 193 deps.configReader.EXPECT().ReadConfig(path.Join(utils.Home(), "snap/lxd/current/.config/lxc/config.yml")).Return(lxd.LXCConfig{ 194 DefaultRemote: "localhost", 195 Remotes: map[string]lxd.LXCRemoteConfig{ 196 "nuc1": { 197 Addr: "https://10.0.0.1:8443", 198 AuthType: "certificate", 199 Protocol: "lxd", 200 Public: false, 201 }, 202 }, 203 }, nil) 204 205 got, err := cloudDetector.DetectCloud("nuc1") 206 c.Assert(err, jc.ErrorIsNil) 207 c.Assert(got, jc.DeepEquals, cloud.Cloud{ 208 Name: "nuc1", 209 Type: "lxd", 210 Endpoint: "https://10.0.0.1:8443", 211 AuthTypes: []cloud.AuthType{ 212 cloud.CertificateAuthType, 213 }, 214 Regions: []cloud.Region{{ 215 Name: "default", 216 Endpoint: "https://10.0.0.1:8443", 217 }}, 218 Description: "LXD Cluster", 219 }) 220 } 221 222 func (s *providerSuite) TestRemoteDetectCloudWithConfigError(c *gc.C) { 223 ctrl := gomock.NewController(c) 224 defer ctrl.Finish() 225 226 deps := s.createProvider(ctrl) 227 cloudDetector := deps.provider.(environs.CloudDetector) 228 229 deps.configReader.EXPECT().ReadConfig(path.Join(osenv.JujuXDGDataHomePath("lxd"), "config.yml")).Return(lxd.LXCConfig{}, errors.New("bad")) 230 deps.configReader.EXPECT().ReadConfig(path.Join(utils.Home(), ".config/lxc/config.yml")).Return(lxd.LXCConfig{}, errors.New("bad")) 231 deps.configReader.EXPECT().ReadConfig(path.Join(utils.Home(), "snap/lxd/current/.config/lxc/config.yml")).Return(lxd.LXCConfig{}, errors.New("bad")) 232 deps.configReader.EXPECT().ReadConfig(path.Join(utils.Home(), "snap/lxd/common/config/config.yml")).Return(lxd.LXCConfig{}, errors.New("bad")) 233 234 _, err := cloudDetector.DetectCloud("nuc1") 235 c.Assert(err, gc.ErrorMatches, `cloud nuc1 not found`) 236 } 237 238 func (s *providerSuite) TestDetectCloudError(c *gc.C) { 239 ctrl := gomock.NewController(c) 240 defer ctrl.Finish() 241 242 deps := s.createProvider(ctrl) 243 deps.configReader.EXPECT().ReadConfig(path.Join(osenv.JujuXDGDataHomePath("lxd"), "config.yml")).Return(lxd.LXCConfig{}, errors.New("bad")) 244 deps.configReader.EXPECT().ReadConfig(path.Join(utils.Home(), ".config/lxc/config.yml")).Return(lxd.LXCConfig{}, errors.New("bad")) 245 deps.configReader.EXPECT().ReadConfig(path.Join(utils.Home(), "snap/lxd/current/.config/lxc/config.yml")).Return(lxd.LXCConfig{}, errors.New("bad")) 246 deps.configReader.EXPECT().ReadConfig(path.Join(utils.Home(), "snap/lxd/common/config/config.yml")).Return(lxd.LXCConfig{}, errors.New("bad")) 247 248 cloudDetector := deps.provider.(environs.CloudDetector) 249 250 _, err := cloudDetector.DetectCloud("foo") 251 c.Assert(err, gc.ErrorMatches, `cloud foo not found`) 252 } 253 254 func (s *providerSuite) assertLocalhostCloud(c *gc.C, found cloud.Cloud) { 255 c.Assert(found, jc.DeepEquals, cloud.Cloud{ 256 Name: "localhost", 257 Type: "lxd", 258 AuthTypes: []cloud.AuthType{ 259 cloud.CertificateAuthType, 260 }, 261 Regions: []cloud.Region{{ 262 Name: "localhost", 263 }}, 264 Description: "LXD Container Hypervisor", 265 }) 266 } 267 268 func (s *providerSuite) TestFinalizeCloud(c *gc.C) { 269 ctrl := gomock.NewController(c) 270 defer ctrl.Finish() 271 272 deps := s.createProvider(ctrl) 273 server := lxd.NewMockServer(ctrl) 274 finalizer := deps.provider.(environs.CloudFinalizer) 275 276 deps.factory.EXPECT().LocalServer().Return(server, nil) 277 server.EXPECT().LocalBridgeName().Return("lxdbr0") 278 deps.factory.EXPECT().LocalServerAddress().Return("1.2.3.4:1234", nil) 279 280 var ctx mockContext 281 out, err := finalizer.FinalizeCloud(&ctx, cloud.Cloud{ 282 Name: "localhost", 283 Type: "lxd", 284 AuthTypes: []cloud.AuthType{cloud.CertificateAuthType}, 285 Regions: []cloud.Region{{ 286 Name: "localhost", 287 }}, 288 }) 289 c.Assert(err, jc.ErrorIsNil) 290 c.Assert(out, jc.DeepEquals, cloud.Cloud{ 291 Name: "localhost", 292 Type: "lxd", 293 AuthTypes: []cloud.AuthType{cloud.CertificateAuthType}, 294 Endpoint: "1.2.3.4:1234", 295 Regions: []cloud.Region{{ 296 Name: "localhost", 297 Endpoint: "1.2.3.4:1234", 298 }}, 299 }) 300 ctx.CheckCallNames(c, "Verbosef") 301 ctx.CheckCall( 302 c, 0, "Verbosef", "Resolved LXD host address on bridge %s: %s", 303 []interface{}{"lxdbr0", "1.2.3.4:1234"}, 304 ) 305 } 306 307 func (s *providerSuite) TestFinalizeCloudWithRemoteProvider(c *gc.C) { 308 ctrl := gomock.NewController(c) 309 defer ctrl.Finish() 310 311 deps := s.createProvider(ctrl) 312 finalizer := deps.provider.(environs.CloudFinalizer) 313 314 var ctx mockContext 315 out, err := finalizer.FinalizeCloud(&ctx, cloud.Cloud{ 316 Name: "nuc8", 317 Type: "lxd", 318 Endpoint: "http://10.0.0.1:8443", 319 AuthTypes: []cloud.AuthType{cloud.CertificateAuthType}, 320 Regions: []cloud.Region{}, 321 }) 322 c.Assert(err, jc.ErrorIsNil) 323 c.Assert(out, jc.DeepEquals, cloud.Cloud{ 324 Name: "nuc8", 325 Type: "lxd", 326 AuthTypes: []cloud.AuthType{cloud.CertificateAuthType}, 327 Endpoint: "http://10.0.0.1:8443", 328 Regions: []cloud.Region{{ 329 Name: "default", 330 Endpoint: "http://10.0.0.1:8443", 331 }}, 332 }) 333 } 334 335 func (s *providerSuite) TestFinalizeCloudWithRemoteProviderWithOnlyRegionEndpoint(c *gc.C) { 336 ctrl := gomock.NewController(c) 337 defer ctrl.Finish() 338 339 deps := s.createProvider(ctrl) 340 cloudFinalizer := deps.provider.(environs.CloudFinalizer) 341 342 cloudSpec := cloud.Cloud{ 343 Name: "foo", 344 Type: "lxd", 345 AuthTypes: []cloud.AuthType{cloud.CertificateAuthType}, 346 Regions: []cloud.Region{{ 347 Name: "bar", 348 Endpoint: "https://321.321.12.12", 349 }}, 350 } 351 352 ctx := testing.NewMockFinalizeCloudContext(ctrl) 353 got, err := cloudFinalizer.FinalizeCloud(ctx, cloudSpec) 354 c.Assert(err, jc.ErrorIsNil) 355 c.Assert(got, gc.DeepEquals, cloudSpec) 356 } 357 358 func (s *providerSuite) TestFinalizeCloudWithRemoteProviderWithMixedRegions(c *gc.C) { 359 ctrl := gomock.NewController(c) 360 defer ctrl.Finish() 361 362 deps := s.createProvider(ctrl) 363 cloudFinalizer := deps.provider.(environs.CloudFinalizer) 364 365 server := lxd.NewMockServer(ctrl) 366 367 deps.factory.EXPECT().LocalServer().Return(server, nil) 368 server.EXPECT().LocalBridgeName().Return("lxdbr0") 369 deps.factory.EXPECT().LocalServerAddress().Return("https://192.0.0.1:8443", nil) 370 371 cloudSpec := cloud.Cloud{ 372 Name: "localhost", 373 Type: "lxd", 374 AuthTypes: []cloud.AuthType{cloud.CertificateAuthType}, 375 Regions: []cloud.Region{{ 376 Name: "bar", 377 Endpoint: "https://321.321.12.12", 378 }}, 379 } 380 381 ctx := testing.NewMockFinalizeCloudContext(ctrl) 382 ctx.EXPECT().Verbosef("Resolved LXD host address on bridge %s: %s", "lxdbr0", "https://192.0.0.1:8443") 383 384 got, err := cloudFinalizer.FinalizeCloud(ctx, cloudSpec) 385 c.Assert(err, jc.ErrorIsNil) 386 c.Assert(got, gc.DeepEquals, cloud.Cloud{ 387 Name: "localhost", 388 Type: "lxd", 389 Endpoint: "https://192.0.0.1:8443", 390 AuthTypes: []cloud.AuthType{cloud.CertificateAuthType}, 391 Regions: []cloud.Region{{ 392 Name: "bar", 393 Endpoint: "https://321.321.12.12", 394 }}, 395 }) 396 } 397 398 func (s *providerSuite) TestFinalizeCloudWithRemoteProviderWithNoRegion(c *gc.C) { 399 ctrl := gomock.NewController(c) 400 defer ctrl.Finish() 401 402 deps := s.createProvider(ctrl) 403 cloudFinalizer := deps.provider.(environs.CloudFinalizer) 404 405 cloudSpec := cloud.Cloud{ 406 Name: "test", 407 Type: "lxd", 408 Endpoint: "https://192.0.0.1:8443", 409 AuthTypes: []cloud.AuthType{cloud.CertificateAuthType}, 410 Regions: []cloud.Region{}, 411 } 412 413 ctx := testing.NewMockFinalizeCloudContext(ctrl) 414 415 got, err := cloudFinalizer.FinalizeCloud(ctx, cloudSpec) 416 c.Assert(err, jc.ErrorIsNil) 417 c.Assert(got, gc.DeepEquals, cloud.Cloud{ 418 Name: "test", 419 Type: "lxd", 420 Endpoint: "https://192.0.0.1:8443", 421 AuthTypes: []cloud.AuthType{cloud.CertificateAuthType}, 422 Regions: []cloud.Region{{ 423 Name: "default", 424 Endpoint: "https://192.0.0.1:8443", 425 }}, 426 }) 427 } 428 429 func (s *providerSuite) TestFinalizeCloudNotListening(c *gc.C) { 430 ctrl := gomock.NewController(c) 431 defer ctrl.Finish() 432 433 deps := s.createProvider(ctrl) 434 cloudFinalizer := deps.provider.(environs.CloudFinalizer) 435 436 deps.factory.EXPECT().LocalServer().Return(nil, errors.New("bad")) 437 438 ctx := testing.NewMockFinalizeCloudContext(ctrl) 439 _, err := cloudFinalizer.FinalizeCloud(ctx, cloud.Cloud{ 440 Name: "localhost", 441 Type: "lxd", 442 AuthTypes: []cloud.AuthType{cloud.CertificateAuthType}, 443 Regions: []cloud.Region{{ 444 Name: "bar", 445 }}, 446 }) 447 c.Assert(err, gc.NotNil) 448 c.Assert(err, gc.ErrorMatches, "bad") 449 } 450 451 func (s *providerSuite) TestDetectRegions(c *gc.C) { 452 ctrl := gomock.NewController(c) 453 defer ctrl.Finish() 454 455 deps := s.createProvider(ctrl) 456 cloudDetector := deps.provider.(environs.CloudRegionDetector) 457 458 regions, err := cloudDetector.DetectRegions() 459 c.Assert(err, jc.ErrorIsNil) 460 c.Assert(regions, jc.DeepEquals, []cloud.Region{{Name: lxdnames.DefaultLocalRegion}}) 461 } 462 463 func (s *providerSuite) TestValidate(c *gc.C) { 464 ctrl := gomock.NewController(c) 465 defer ctrl.Finish() 466 467 deps := s.createProvider(ctrl) 468 469 validCfg, err := deps.provider.Validate(s.Config, nil) 470 c.Assert(err, jc.ErrorIsNil) 471 validAttrs := validCfg.AllAttrs() 472 473 c.Check(s.Config.AllAttrs(), gc.DeepEquals, validAttrs) 474 } 475 476 func (s *providerSuite) TestValidateWithInvalidConfig(c *gc.C) { 477 ctrl := gomock.NewController(c) 478 defer ctrl.Finish() 479 480 deps := s.createProvider(ctrl) 481 482 config, err := jujutesting.ModelConfig(c).Apply(map[string]interface{}{ 483 "value": int64(1), 484 }) 485 c.Assert(err, gc.IsNil) 486 487 _, err = deps.provider.Validate(config, nil) 488 c.Assert(err, gc.NotNil) 489 } 490 491 func (s *providerSuite) TestCloudSchema(c *gc.C) { 492 ctrl := gomock.NewController(c) 493 defer ctrl.Finish() 494 495 deps := s.createProvider(ctrl) 496 497 config := ` 498 auth-types: [certificate] 499 endpoint: http://foo.com/lxd 500 `[1:] 501 var v interface{} 502 err := yaml.Unmarshal([]byte(config), &v) 503 c.Assert(err, jc.ErrorIsNil) 504 v, err = utils.ConformYAML(v) 505 c.Assert(err, jc.ErrorIsNil) 506 507 err = deps.provider.CloudSchema().Validate(v) 508 c.Assert(err, jc.ErrorIsNil) 509 } 510 511 func (s *providerSuite) TestPingFailWithNoEndpoint(c *gc.C) { 512 server := httptest.NewTLSServer(http.HandlerFunc(http.NotFound)) 513 defer server.Close() 514 515 p, err := environs.Provider("lxd") 516 c.Assert(err, jc.ErrorIsNil) 517 err = p.Ping(context.NewEmptyCloudCallContext(), server.URL) 518 c.Assert(err, gc.ErrorMatches, fmt.Sprintf( 519 "no lxd server running at %[1]s: Failed to fetch %[1]s/1.0: 404 Not Found", 520 server.URL)) 521 } 522 523 func (s *providerSuite) TestPingFailWithHTTP(c *gc.C) { 524 server := httptest.NewServer(http.HandlerFunc(http.NotFound)) 525 defer server.Close() 526 527 p, err := environs.Provider("lxd") 528 c.Assert(err, jc.ErrorIsNil) 529 err = p.Ping(context.NewEmptyCloudCallContext(), server.URL) 530 httpsURL := "https://" + strings.TrimPrefix(server.URL, "http://") 531 c.Assert(err, gc.ErrorMatches, fmt.Sprintf( 532 `no lxd server running at %[1]s: Get "%[1]s/1.0": http: server gave HTTP response to HTTPS client`, 533 httpsURL)) 534 } 535 536 type ProviderFunctionalSuite struct { 537 lxd.BaseSuite 538 539 provider environs.EnvironProvider 540 } 541 542 func (s *ProviderFunctionalSuite) SetUpTest(c *gc.C) { 543 s.BaseSuite.SetUpTest(c) 544 545 provider, err := environs.Provider("lxd") 546 c.Assert(err, jc.ErrorIsNil) 547 548 s.provider = provider 549 } 550 551 func (s *ProviderFunctionalSuite) TestOpen(c *gc.C) { 552 env, err := environs.Open(stdcontext.TODO(), s.provider, environs.OpenParams{ 553 Cloud: lxdCloudSpec(), 554 Config: s.Config, 555 }) 556 c.Assert(err, jc.ErrorIsNil) 557 envConfig := env.Config() 558 559 c.Check(envConfig.Name(), gc.Equals, "testmodel") 560 } 561 562 func (s *ProviderFunctionalSuite) TestPrepareConfig(c *gc.C) { 563 cfg, err := s.provider.PrepareConfig(environs.PrepareConfigParams{ 564 Cloud: lxdCloudSpec(), 565 Config: s.Config, 566 }) 567 c.Assert(err, jc.ErrorIsNil) 568 c.Check(cfg, gc.NotNil) 569 } 570 571 func (s *ProviderFunctionalSuite) TestPrepareConfigUnsupportedEndpointScheme(c *gc.C) { 572 cloudSpec := lxdCloudSpec() 573 cloudSpec.Endpoint = "unix://foo" 574 _, err := s.provider.PrepareConfig(environs.PrepareConfigParams{ 575 Cloud: cloudSpec, 576 Config: s.Config, 577 }) 578 c.Assert(err, gc.ErrorMatches, `validating cloud spec: invalid URL "unix://foo": only HTTPS is supported`) 579 } 580 581 func (s *ProviderFunctionalSuite) TestPrepareConfigUnsupportedAuthType(c *gc.C) { 582 cred := cloud.NewCredential("foo", nil) 583 _, err := s.provider.PrepareConfig(environs.PrepareConfigParams{ 584 Cloud: environscloudspec.CloudSpec{ 585 Type: "lxd", 586 Name: "remotehost", 587 Credential: &cred, 588 }, 589 }) 590 c.Assert(err, gc.ErrorMatches, `validating cloud spec: "foo" auth-type not supported`) 591 } 592 593 func (s *ProviderFunctionalSuite) TestPrepareConfigInvalidCertificateAttrs(c *gc.C) { 594 cred := cloud.NewCredential(cloud.CertificateAuthType, map[string]string{}) 595 _, err := s.provider.PrepareConfig(environs.PrepareConfigParams{ 596 Cloud: environscloudspec.CloudSpec{ 597 Type: "lxd", 598 Name: "remotehost", 599 Credential: &cred, 600 }, 601 }) 602 c.Assert(err, gc.ErrorMatches, `validating cloud spec: certificate credentials not valid`) 603 } 604 605 func (s *ProviderFunctionalSuite) TestPrepareConfigEmptyAuthNonLocal(c *gc.C) { 606 cred := cloud.NewEmptyCredential() 607 _, err := s.provider.PrepareConfig(environs.PrepareConfigParams{ 608 Cloud: environscloudspec.CloudSpec{ 609 Type: "lxd", 610 Name: "remotehost", 611 Endpoint: "8.8.8.8", 612 Credential: &cred, 613 }, 614 }) 615 c.Assert(err, gc.ErrorMatches, `validating cloud spec: "empty" auth-type not supported`) 616 } 617 618 type mockContext struct { 619 gitjujutesting.Stub 620 } 621 622 func (c *mockContext) Verbosef(f string, args ...interface{}) { 623 c.MethodCall(c, "Verbosef", f, args) 624 }