Skip to content

Commit 7ffa1d8

Browse files
committed
Merge branch '2.6' into merge-26-develop-2506
2 parents d13b59a + 4c98b64 commit 7ffa1d8

File tree

12 files changed

+243
-51
lines changed

12 files changed

+243
-51
lines changed

cmd/juju/commands/bootstrap.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/juju/cmd"
1616
"github.com/juju/errors"
1717
"github.com/juju/gnuflag"
18+
"github.com/juju/naturalsort"
1819
"github.com/juju/schema"
1920
"github.com/juju/utils"
2021
"github.com/juju/utils/featureflag"
@@ -505,6 +506,27 @@ to create a new model to deploy k8s workloads.
505506
if err != nil {
506507
return errors.Trace(err)
507508
}
509+
// If region is specified by the user, validate it here.
510+
// lp#1632735
511+
if c.Region != "" {
512+
_, err := jujucloud.RegionByName(cloud.Regions, c.Region)
513+
if err != nil {
514+
allRegions := make([]string, len(cloud.Regions))
515+
for i, one := range cloud.Regions {
516+
allRegions[i] = one.Name
517+
}
518+
if len(allRegions) > 0 {
519+
naturalsort.Sort(allRegions)
520+
plural := "s are"
521+
if len(allRegions) == 1 {
522+
plural = " is"
523+
}
524+
ctx.Infof("Available cloud region%v %v", plural, strings.Join(allRegions, ", "))
525+
}
526+
return errors.NotValidf("region %q for cloud %q", c.Region, c.Cloud)
527+
}
528+
}
529+
508530
isCAASController := jujucloud.CloudIsCAAS(cloud)
509531

510532
// Custom clouds may not have explicitly declared support for any auth-

cmd/juju/commands/bootstrap_test.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1456,9 +1456,8 @@ func (s *BootstrapSuite) TestBootstrapCloudNoRegionsOneSpecified(c *gc.C) {
14561456
c, s.newBootstrapCommand(), "dummy-cloud-without-regions/my-region", "ctrl",
14571457
"--config", "default-series=precise",
14581458
)
1459-
c.Check(cmdtesting.Stderr(ctx), gc.Matches,
1460-
"region \"my-region\" not found \\(expected one of \\[\\]\\)\n\n.*\n")
1461-
c.Assert(err, gc.Equals, cmd.ErrSilent)
1459+
c.Check(cmdtesting.Stderr(ctx), gc.Equals, "")
1460+
c.Assert(err, gc.ErrorMatches, `region "my-region" for cloud "dummy-cloud-without-regions" not valid`)
14621461
}
14631462

14641463
func (s *BootstrapSuite) TestBootstrapProviderNoCredentials(c *gc.C) {
@@ -1516,9 +1515,9 @@ func (s *BootstrapSuite) TestBootstrapProviderFileCredential(c *gc.C) {
15161515
func (s *BootstrapSuite) TestBootstrapProviderDetectRegionsInvalid(c *gc.C) {
15171516
s.patchVersionAndSeries(c, "raring")
15181517
ctx, err := cmdtesting.RunCommand(c, s.newBootstrapCommand(), "dummy/not-dummy", "ctrl")
1519-
c.Assert(err, gc.Equals, cmd.ErrSilent)
1518+
c.Assert(err, gc.ErrorMatches, `region "not-dummy" for cloud "dummy" not valid`)
15201519
stderr := strings.Replace(cmdtesting.Stderr(ctx), "\n", "", -1)
1521-
c.Assert(stderr, gc.Matches, `region "not-dummy" not found \(expected one of \["dummy"\]\)Specify an alternative region, or try "juju update-clouds".`)
1520+
c.Assert(stderr, gc.Matches, `Available cloud region is dummy`)
15221521
}
15231522

15241523
func (s *BootstrapSuite) TestBootstrapProviderManyCredentialsCloudNoAuthTypes(c *gc.C) {
@@ -1931,6 +1930,14 @@ sa-east-1
19311930
`[1:])
19321931
}
19331932

1933+
func (s *BootstrapSuite) TestBootstrapInvalidRegion(c *gc.C) {
1934+
resetJujuXDGDataHome(c)
1935+
ctx, err := cmdtesting.RunCommand(c, s.newBootstrapCommand(), "aws/eu-west")
1936+
c.Assert(err, gc.ErrorMatches, `region "eu-west" for cloud "aws" not valid`)
1937+
c.Assert(cmdtesting.Stderr(ctx), gc.Equals, "Available cloud regions are ap-northeast-1, ap-northeast-2, ap-south-1, ap-southeast-1, ap-southeast-2, ca-central-1, eu-central-1, eu-west-1, eu-west-2, eu-west-3, sa-east-1, us-east-1, us-east-2, us-west-1, us-west-2\n")
1938+
c.Assert(cmdtesting.Stdout(ctx), gc.Equals, ``)
1939+
}
1940+
19341941
func (s *BootstrapSuite) TestBootstrapPrintCloudRegionsNoSuchCloud(c *gc.C) {
19351942
resetJujuXDGDataHome(c)
19361943
_, err := cmdtesting.RunCommand(c, s.newBootstrapCommand(), "--regions", "foo")

provider/azure/config.go

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package azure
66
import (
77
"strings"
88

9+
"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2018-08-01/network"
910
"github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2018-07-01/storage"
1011
"github.com/juju/errors"
1112
"github.com/juju/schema"
@@ -15,8 +16,15 @@ import (
1516
)
1617

1718
const (
19+
// configAttrStorageAccountType mirrors the storage SKU name in the Azure SDK
20+
//
21+
// The term "storage account" has been replaced with "SKU name" in recent
22+
// Azure SDK, but we keep it to maintain backwards-compatibility.
1823
configAttrStorageAccountType = "storage-account-type"
1924

25+
// configAttrLoadBalancerSkuName mirrors the LoadBalancerSkuName type in the Azure SDK
26+
configAttrLoadBalancerSkuName = "load-balancer-sku-name"
27+
2028
// The below bits are internal book-keeping things, rather than
2129
// configuration. Config is just what we have to work with.
2230

@@ -26,11 +34,13 @@ const (
2634
)
2735

2836
var configFields = schema.Fields{
29-
configAttrStorageAccountType: schema.String(),
37+
configAttrStorageAccountType: schema.String(),
38+
configAttrLoadBalancerSkuName: schema.String(),
3039
}
3140

3241
var configDefaults = schema.Defaults{
33-
configAttrStorageAccountType: string(storage.StandardLRS),
42+
configAttrStorageAccountType: string(storage.StandardLRS),
43+
configAttrLoadBalancerSkuName: string(network.LoadBalancerSkuNameStandard),
3444
}
3545

3646
var immutableConfigAttributes = []string{
@@ -39,11 +49,26 @@ var immutableConfigAttributes = []string{
3949

4050
type azureModelConfig struct {
4151
*config.Config
42-
storageAccountType string
52+
storageAccountType string
53+
loadBalancerSkuName string
54+
}
55+
56+
// knownStorageAccountTypes returns a list of valid storage SKU names.
57+
//
58+
// The term "account type" is is used in previous versions of the Azure SDK.
59+
func knownStorageAccountTypes() (accountTypes []string) {
60+
for _, name := range storage.PossibleSkuNameValues() {
61+
accountTypes = append(accountTypes, string(name))
62+
}
63+
return accountTypes
4364
}
4465

45-
var knownStorageAccountTypes = []string{
46-
"Standard_LRS", "Standard_GRS", "Standard_RAGRS", "Standard_ZRS", "Premium_LRS",
66+
// knownLoadBalancerSkuNames returns a list of valid load balancer SKU names.
67+
func knownLoadBalancerSkuNames() (skus []string) {
68+
for _, name := range network.PossibleLoadBalancerSkuNameValues() {
69+
skus = append(skus, string(name))
70+
}
71+
return skus
4772
}
4873

4974
// Validate ensures that the provided configuration is valid for this
@@ -114,28 +139,57 @@ Please choose a model name of no more than %d characters.`,
114139
if !isKnownStorageAccountType(storageAccountType) {
115140
return nil, errors.Errorf(
116141
"invalid storage account type %q, expected one of: %q",
117-
storageAccountType, knownStorageAccountTypes,
142+
storageAccountType, knownStorageAccountTypes(),
118143
)
119144
}
120145

146+
loadBalancerSkuName, ok := validated[configAttrLoadBalancerSkuName].(string)
147+
if ok {
148+
loadBalancerSkuNameTitle := strings.Title(loadBalancerSkuName)
149+
if loadBalancerSkuName != loadBalancerSkuNameTitle {
150+
loadBalancerSkuName = loadBalancerSkuNameTitle
151+
logger.Infof("using %q for config parameter %s", loadBalancerSkuName, configAttrLoadBalancerSkuName)
152+
}
153+
if !isKnownLoadBalancerSkuName(loadBalancerSkuName) {
154+
return nil, errors.Errorf(
155+
"invalid load balancer SKU name %q, expected one of: %q",
156+
loadBalancerSkuName, knownLoadBalancerSkuNames(),
157+
)
158+
}
159+
} else {
160+
loadBalancerSkuName = string(network.LoadBalancerSkuNameStandard)
161+
}
162+
121163
azureConfig := &azureModelConfig{
122164
newCfg,
123165
storageAccountType,
166+
loadBalancerSkuName,
124167
}
125168
return azureConfig, nil
126169
}
127170

128171
// isKnownStorageAccountType reports whether or not the given string identifies
129172
// a known storage account type.
130173
func isKnownStorageAccountType(t string) bool {
131-
for _, knownStorageAccountType := range knownStorageAccountTypes {
174+
for _, knownStorageAccountType := range knownStorageAccountTypes() {
132175
if t == knownStorageAccountType {
133176
return true
134177
}
135178
}
136179
return false
137180
}
138181

182+
// isKnownLoadBalancerSkuName reports whether or not the given string
183+
// a valid storage SKU within the Azure SDK
184+
func isKnownLoadBalancerSkuName(n string) bool {
185+
for _, skuName := range knownLoadBalancerSkuNames() {
186+
if n == skuName {
187+
return true
188+
}
189+
}
190+
return false
191+
}
192+
139193
// canonicalLocation returns the canonicalized location string. This involves
140194
// stripping whitespace, and lowercasing. The ARM APIs do not support embedded
141195
// whitespace, whereas the old Service Management APIs used to; we allow the

provider/azure/config_test.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,14 @@ func (s *configSuite) TestValidateNew(c *gc.C) {
4242
func (s *configSuite) TestValidateInvalidStorageAccountType(c *gc.C) {
4343
s.assertConfigInvalid(
4444
c, testing.Attrs{"storage-account-type": "savings"},
45-
`invalid storage account type "savings", expected one of: \["Standard_LRS" "Standard_GRS" "Standard_RAGRS" "Standard_ZRS" "Premium_LRS"\]`,
45+
`invalid storage account type "savings", expected one of: \["Premium_LRS" "Premium_ZRS" "Standard_GRS" "Standard_LRS" "Standard_RAGRS" "Standard_ZRS"\]`,
46+
)
47+
}
48+
49+
func (s *configSuite) TestValidateInvalidLoadBalancerSkuName(c *gc.C) {
50+
s.assertConfigInvalid(
51+
c, testing.Attrs{"load-balancer-sku-name": "premium"},
52+
`invalid load balancer SKU name "Premium", expected one of: \["Basic" "Standard"\]`,
4653
)
4754
}
4855

@@ -71,6 +78,19 @@ func (s *configSuite) TestValidateStorageAccountTypeCantChange(c *gc.C) {
7178
c.Assert(err, gc.ErrorMatches, `cannot change immutable "storage-account-type" config \(Standard_LRS -> Premium_LRS\)`)
7279
}
7380

81+
func (s *configSuite) TestValidateLoadBalancerSkuNameCanChange(c *gc.C) {
82+
cfgOld := makeTestModelConfig(c, testing.Attrs{"load-balancer-sku-name": "Standard"})
83+
_, err := s.provider.Validate(cfgOld, cfgOld)
84+
c.Assert(err, jc.ErrorIsNil)
85+
86+
cfgNew := makeTestModelConfig(c, testing.Attrs{"load-balancer-sku-name": "Basic"})
87+
_, err = s.provider.Validate(cfgNew, cfgOld)
88+
c.Assert(err, jc.ErrorIsNil)
89+
90+
_, err = s.provider.Validate(cfgOld, cfgNew)
91+
c.Assert(err, jc.ErrorIsNil)
92+
}
93+
7494
func (s *configSuite) assertConfigValid(c *gc.C, attrs testing.Attrs) {
7595
cfg := makeTestModelConfig(c, attrs)
7696
_, err := s.provider.Validate(cfg, nil)

provider/azure/environ.go

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,7 @@ func (env *azureEnviron) StartInstance(ctx context.ProviderCallContext, args env
495495
}
496496
if seriesOS == os.Windows {
497497
if instanceSpec.InstanceType.RootDisk < windowsMinRootDiskMB {
498+
logger.Infof("root disk size has been increased to 127GiB")
498499
instanceSpec.InstanceType.RootDisk = windowsMinRootDiskMB
499500
}
500501
}
@@ -654,7 +655,7 @@ func (env *azureEnviron) createVirtualMachine(
654655
)
655656
var (
656657
availabilitySetProperties interface{}
657-
availabilityStorageOptions *storage.Sku
658+
availabilityStorageOptions armtemplates.Sku
658659
)
659660
if maybeStorageAccount == nil {
660661
// This model uses managed disks; we must create
@@ -669,9 +670,7 @@ func (env *azureEnviron) createVirtualMachine(
669670
PlatformFaultDomainCount: to.Int32Ptr(maxFaultDomains(env.location)),
670671
}
671672
// Availability needs to be 'Aligned' to support managed disks.
672-
availabilityStorageOptions = &storage.Sku{
673-
Name: "Aligned",
674-
}
673+
availabilityStorageOptions.Name = "Aligned"
675674
}
676675
resources = append(resources, armtemplates.Resource{
677676
APIVersion: computeAPIVersion,
@@ -680,7 +679,7 @@ func (env *azureEnviron) createVirtualMachine(
680679
Location: env.location,
681680
Tags: envTags,
682681
Properties: availabilitySetProperties,
683-
StorageSku: availabilityStorageOptions,
682+
Sku: &availabilityStorageOptions,
684683
})
685684
availabilitySetSubResource = &compute.SubResource{
686685
ID: to.StringPtr(availabilitySetId),
@@ -690,16 +689,20 @@ func (env *azureEnviron) createVirtualMachine(
690689

691690
publicIPAddressName := vmName + "-public-ip"
692691
publicIPAddressId := fmt.Sprintf(`[resourceId('Microsoft.Network/publicIPAddresses', '%s')]`, publicIPAddressName)
692+
publicIPAddressAllocationMethod := network.Static
693+
if env.config.loadBalancerSkuName == string(network.LoadBalancerSkuNameBasic) {
694+
publicIPAddressAllocationMethod = network.Dynamic // preserve the settings that were used in Juju 2.4 and earlier
695+
}
693696
resources = append(resources, armtemplates.Resource{
694697
APIVersion: networkAPIVersion,
695698
Type: "Microsoft.Network/publicIPAddresses",
696699
Name: publicIPAddressName,
697700
Location: env.location,
698701
Tags: vmTags,
699-
StorageSku: &storage.Sku{Name: "Standard", Tier: "Regional"},
702+
Sku: &armtemplates.Sku{Name: env.config.loadBalancerSkuName},
700703
Properties: &network.PublicIPAddressPropertiesFormat{
701704
PublicIPAddressVersion: network.IPv4,
702-
PublicIPAllocationMethod: network.Static,
705+
PublicIPAllocationMethod: publicIPAddressAllocationMethod,
703706
},
704707
})
705708

provider/azure/environ_test.go

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -987,9 +987,7 @@ func (s *environSuite) assertStartInstanceRequests(
987987
Name: storageAccountName,
988988
Location: "westus",
989989
Tags: to.StringMap(s.envTags),
990-
StorageSku: &storage.Sku{
991-
Name: storage.SkuName("Standard_LRS"),
992-
},
990+
Sku: &armtemplates.Sku{Name: "Standard_LRS"},
993991
})
994992
vmDependsOn = append(vmDependsOn,
995993
`[resourceId('Microsoft.Storage/storageAccounts', '`+storageAccountName+`')]`,
@@ -1008,15 +1006,13 @@ func (s *environSuite) assertStartInstanceRequests(
10081006
)
10091007
var (
10101008
availabilitySetProperties interface{}
1011-
availabilityStorageOptions *storage.Sku
1009+
availabilityStorageOptions armtemplates.Sku
10121010
)
10131011
if !args.unmanagedStorage {
10141012
availabilitySetProperties = &compute.AvailabilitySetProperties{
10151013
PlatformFaultDomainCount: to.Int32Ptr(3),
10161014
}
1017-
availabilityStorageOptions = &storage.Sku{
1018-
Name: "Aligned",
1019-
}
1015+
availabilityStorageOptions.Name = "Aligned"
10201016
}
10211017
templateResources = append(templateResources, armtemplates.Resource{
10221018
APIVersion: computeAPIVersion,
@@ -1025,7 +1021,7 @@ func (s *environSuite) assertStartInstanceRequests(
10251021
Location: "westus",
10261022
Tags: to.StringMap(s.envTags),
10271023
Properties: availabilitySetProperties,
1028-
StorageSku: availabilityStorageOptions,
1024+
Sku: &availabilityStorageOptions,
10291025
})
10301026
availabilitySetSubResource = &compute.SubResource{
10311027
ID: to.StringPtr(availabilitySetId),
@@ -1059,7 +1055,7 @@ func (s *environSuite) assertStartInstanceRequests(
10591055
PublicIPAllocationMethod: network.Static,
10601056
PublicIPAddressVersion: "IPv4",
10611057
},
1062-
StorageSku: &storage.Sku{Name: "Standard", Tier: "Regional"},
1058+
Sku: &armtemplates.Sku{Name: "Standard"},
10631059
}, {
10641060
APIVersion: networkAPIVersion,
10651061
Type: "Microsoft.Network/networkInterfaces",

provider/azure/environprovider.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ type ProviderConfig struct {
6565

6666
// AzureCLI is the interface the to Azure CLI (az) command.
6767
AzureCLI AzureCLI
68+
69+
// LoadBalancerSkuName is the load balancer SKU name.
70+
// Legal values are determined by the Azure SDK.
71+
LoadBalancerSkuName string
6872
}
6973

7074
// Validate validates the Azure provider configuration.

provider/azure/internal/armtemplates/template.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33

44
package armtemplates
55

6-
import "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2018-07-01/storage"
7-
86
const (
97
schema = "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#"
108
contentVersion = "1.0.0.0"
@@ -29,6 +27,13 @@ func (t *Template) Map() (map[string]interface{}, error) {
2927
return m, nil
3028
}
3129

30+
// Sku represents an Azure SKU. Each API (compute/networking/storage)
31+
// defines its own SKU types, but we use a common type because we
32+
// don't require many fields.
33+
type Sku struct {
34+
Name string `json:"name,omitempty"`
35+
}
36+
3237
// Resource describes a template resource. For information on the
3338
// individual fields, see https://azure.microsoft.com/en-us/documentation/articles/resource-group-authoring-templates/.
3439
type Resource struct {
@@ -43,5 +48,5 @@ type Resource struct {
4348
Resources []Resource `json:"resources,omitempty"`
4449

4550
// Non-uniform attributes.
46-
StorageSku *storage.Sku `json:"sku,omitempty"`
51+
Sku *Sku `json:"sku,omitempty"`
4752
}

provider/azure/storage.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,8 +1001,6 @@ func storageAccountTemplateResource(
10011001
Name: accountName,
10021002
Location: location,
10031003
Tags: envTags,
1004-
StorageSku: &armstorage.Sku{
1005-
Name: armstorage.SkuName(accountType),
1006-
},
1004+
Sku: &armtemplates.Sku{Name: accountType},
10071005
}
10081006
}

0 commit comments

Comments
 (0)