зеркало из https://github.com/Azure/aks-engine.git
feat: use all VMAS fault domains in a region (#1090)
This commit is contained in:
Родитель
2318d1a557
Коммит
10a312534d
13
cmd/scale.go
13
cmd/scale.go
|
@ -223,6 +223,8 @@ func (sc *scaleCmd) run(cmd *cobra.Command, args []string) error {
|
|||
indexes := make([]int, 0)
|
||||
indexToVM := make(map[int]string)
|
||||
if sc.agentPool.IsAvailabilitySets() {
|
||||
availabilitySetIDs := []string{}
|
||||
|
||||
for vmsListPage, err := sc.client.ListVirtualMachines(ctx, sc.resourceGroupName); vmsListPage.NotDone(); err = vmsListPage.Next() {
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get vms in the resource group")
|
||||
|
@ -235,6 +237,10 @@ func (sc *scaleCmd) run(cmd *cobra.Command, args []string) error {
|
|||
continue
|
||||
}
|
||||
|
||||
if vm.AvailabilitySet != nil {
|
||||
availabilitySetIDs = append(availabilitySetIDs, *vm.AvailabilitySet.ID)
|
||||
}
|
||||
|
||||
osPublisher := vm.StorageProfile.ImageReference.Publisher
|
||||
if osPublisher != nil && strings.EqualFold(*osPublisher, "MicrosoftWindowsServer") {
|
||||
_, _, winPoolIndex, index, err = utils.WindowsVMNameParts(vmName)
|
||||
|
@ -260,6 +266,13 @@ func (sc *scaleCmd) run(cmd *cobra.Command, args []string) error {
|
|||
}
|
||||
highestUsedIndex = indexes[len(indexes)-1]
|
||||
|
||||
// set the VMAS platformFaultDomainCount to match the existing value
|
||||
fdCount, err := sc.client.GetAvailabilitySetFaultDomainCount(ctx, sc.resourceGroupName, availabilitySetIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sc.containerService.SetPlatformFaultDomainCount(fdCount)
|
||||
|
||||
// Scale down Scenario
|
||||
if currentNodeCount > sc.newDesiredAgentCount {
|
||||
if sc.masterFQDN == "" {
|
||||
|
|
|
@ -469,6 +469,7 @@ type MasterProfile struct {
|
|||
ImageRef *ImageReference `json:"imageReference,omitempty"`
|
||||
CustomFiles *[]CustomFile `json:"customFiles,omitempty"`
|
||||
AvailabilityProfile string `json:"availabilityProfile"`
|
||||
PlatformFaultDomainCount *int `json:"platformFaultDomainCount"`
|
||||
AgentSubnet string `json:"agentSubnet,omitempty"`
|
||||
AvailabilityZones []string `json:"availabilityZones,omitempty"`
|
||||
SinglePlacementGroup *bool `json:"singlePlacementGroup,omitempty"`
|
||||
|
@ -518,6 +519,7 @@ type AgentPoolProfile struct {
|
|||
Ports []int `json:"ports,omitempty"`
|
||||
ProvisioningState ProvisioningState `json:"provisioningState,omitempty"`
|
||||
AvailabilityProfile string `json:"availabilityProfile"`
|
||||
PlatformFaultDomainCount *int `json:"platformFaultDomainCount"`
|
||||
ScaleSetPriority string `json:"scaleSetPriority,omitempty"`
|
||||
ScaleSetEvictionPolicy string `json:"scaleSetEvictionPolicy,omitempty"`
|
||||
StorageProfile string `json:"storageProfile,omitempty"`
|
||||
|
@ -1842,6 +1844,15 @@ func (cs *ContainerService) GetAzureProdFQDN() string {
|
|||
return FormatProdFQDNByLocation(cs.Properties.MasterProfile.DNSPrefix, cs.Location, cs.Properties.GetCustomCloudName())
|
||||
}
|
||||
|
||||
// SetPlatformFaultDomainCount sets the fault domain count value for all VMASes in a cluster.
|
||||
func (cs *ContainerService) SetPlatformFaultDomainCount(count int) {
|
||||
// Assume that all VMASes in the cluster share a value for platformFaultDomainCount
|
||||
cs.Properties.MasterProfile.PlatformFaultDomainCount = &count
|
||||
for _, pool := range cs.Properties.AgentPoolProfiles {
|
||||
pool.PlatformFaultDomainCount = &count
|
||||
}
|
||||
}
|
||||
|
||||
// FormatAzureProdFQDNByLocation constructs an Azure prod fqdn
|
||||
func FormatAzureProdFQDNByLocation(fqdnPrefix string, location string) string {
|
||||
targetEnv := helpers.GetCloudTargetEnv(location)
|
||||
|
|
|
@ -4956,3 +4956,29 @@ func TestKubernetesConfigIsAddonEnabled(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetPlatformFaultDomainCount(t *testing.T) {
|
||||
// check that the default value is nil
|
||||
cs := CreateMockContainerService("testcluster", defaultTestClusterVer, 1, 3, false)
|
||||
if cs.Properties.MasterProfile.PlatformFaultDomainCount != nil {
|
||||
t.Errorf("expected master platformFaultDomainCount to be nil, not %v", cs.Properties.MasterProfile.PlatformFaultDomainCount)
|
||||
}
|
||||
for _, pool := range cs.Properties.AgentPoolProfiles {
|
||||
if pool.PlatformFaultDomainCount != nil {
|
||||
t.Errorf("expected agent platformFaultDomainCount to be nil, not %v", pool.PlatformFaultDomainCount)
|
||||
}
|
||||
}
|
||||
|
||||
// check that pfdc can be set to legal values
|
||||
for i := 1; i <= 3; i++ {
|
||||
cs.SetPlatformFaultDomainCount(i)
|
||||
if *cs.Properties.MasterProfile.PlatformFaultDomainCount != i {
|
||||
t.Errorf("expected master platformFaultDomainCount to be %d, not %v", i, cs.Properties.MasterProfile.PlatformFaultDomainCount)
|
||||
}
|
||||
for _, pool := range cs.Properties.AgentPoolProfiles {
|
||||
if *pool.PlatformFaultDomainCount != i {
|
||||
t.Errorf("expected agent platformFaultDomainCount to be %d, not %v", i, pool.PlatformFaultDomainCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,6 +67,7 @@ type AzureClient struct {
|
|||
virtualMachineScaleSetVMsClient compute.VirtualMachineScaleSetVMsClient
|
||||
virtualMachineExtensionsClient compute.VirtualMachineExtensionsClient
|
||||
disksClient compute.DisksClient
|
||||
availabilitySetsClient compute.AvailabilitySetsClient
|
||||
|
||||
applicationsClient graphrbac.ApplicationsClient
|
||||
servicePrincipalsClient graphrbac.ServicePrincipalsClient
|
||||
|
@ -348,6 +349,7 @@ func getClient(env azure.Environment, subscriptionID, tenantID string, armAuthor
|
|||
virtualMachineScaleSetVMsClient: compute.NewVirtualMachineScaleSetVMsClientWithBaseURI(env.ResourceManagerEndpoint, subscriptionID),
|
||||
virtualMachineExtensionsClient: compute.NewVirtualMachineExtensionsClientWithBaseURI(env.ResourceManagerEndpoint, subscriptionID),
|
||||
disksClient: compute.NewDisksClientWithBaseURI(env.ResourceManagerEndpoint, subscriptionID),
|
||||
availabilitySetsClient: compute.NewAvailabilitySetsClientWithBaseURI(env.ResourceManagerEndpoint, subscriptionID),
|
||||
|
||||
applicationsClient: graphrbac.NewApplicationsClientWithBaseURI(env.GraphEndpoint, tenantID),
|
||||
servicePrincipalsClient: graphrbac.NewServicePrincipalsClientWithBaseURI(env.GraphEndpoint, tenantID),
|
||||
|
@ -366,6 +368,7 @@ func getClient(env azure.Environment, subscriptionID, tenantID string, armAuthor
|
|||
c.virtualMachineScaleSetsClient.Authorizer = armAuthorizer
|
||||
c.virtualMachineScaleSetVMsClient.Authorizer = armAuthorizer
|
||||
c.disksClient.Authorizer = armAuthorizer
|
||||
c.availabilitySetsClient.Authorizer = armAuthorizer
|
||||
|
||||
c.deploymentsClient.PollingDelay = time.Second * 5
|
||||
c.resourcesClient.PollingDelay = time.Second * 5
|
||||
|
@ -384,6 +387,7 @@ func getClient(env azure.Environment, subscriptionID, tenantID string, armAuthor
|
|||
c.virtualMachineScaleSetsClient.PollingDuration = DefaultARMOperationTimeout
|
||||
c.virtualMachineScaleSetVMsClient.PollingDuration = DefaultARMOperationTimeout
|
||||
c.virtualMachinesClient.PollingDuration = DefaultARMOperationTimeout
|
||||
c.availabilitySetsClient.PollingDuration = DefaultARMOperationTimeout
|
||||
|
||||
c.applicationsClient.Authorizer = graphAuthorizer
|
||||
c.servicePrincipalsClient.Authorizer = graphAuthorizer
|
||||
|
|
|
@ -63,6 +63,7 @@ type AzureClient struct {
|
|||
virtualMachineScaleSetVMsClient compute.VirtualMachineScaleSetVMsClient
|
||||
virtualMachineExtensionsClient compute.VirtualMachineExtensionsClient
|
||||
disksClient compute.DisksClient
|
||||
availabilitySetsClient compute.AvailabilitySetsClient
|
||||
|
||||
applicationsClient graphrbac.ApplicationsClient
|
||||
servicePrincipalsClient graphrbac.ServicePrincipalsClient
|
||||
|
@ -213,6 +214,7 @@ func getClient(env azure.Environment, subscriptionID, tenantID string, armAuthor
|
|||
virtualMachineScaleSetVMsClient: compute.NewVirtualMachineScaleSetVMsClientWithBaseURI(env.ResourceManagerEndpoint, subscriptionID),
|
||||
virtualMachineExtensionsClient: compute.NewVirtualMachineExtensionsClientWithBaseURI(env.ResourceManagerEndpoint, subscriptionID),
|
||||
disksClient: compute.NewDisksClientWithBaseURI(env.ResourceManagerEndpoint, subscriptionID),
|
||||
availabilitySetsClient: compute.NewAvailabilitySetsClientWithBaseURI(env.ResourceManagerEndpoint, subscriptionID),
|
||||
|
||||
applicationsClient: graphrbac.NewApplicationsClientWithBaseURI(env.GraphEndpoint, tenantID),
|
||||
servicePrincipalsClient: graphrbac.NewServicePrincipalsClientWithBaseURI(env.GraphEndpoint, tenantID),
|
||||
|
@ -231,6 +233,7 @@ func getClient(env azure.Environment, subscriptionID, tenantID string, armAuthor
|
|||
c.virtualMachineScaleSetsClient.Authorizer = armAuthorizer
|
||||
c.virtualMachineScaleSetVMsClient.Authorizer = armAuthorizer
|
||||
c.disksClient.Authorizer = armAuthorizer
|
||||
c.availabilitySetsClient.Authorizer = armAuthorizer
|
||||
|
||||
c.deploymentsClient.PollingDelay = time.Second * 5
|
||||
c.resourcesClient.PollingDelay = time.Second * 5
|
||||
|
@ -249,6 +252,7 @@ func getClient(env azure.Environment, subscriptionID, tenantID string, armAuthor
|
|||
c.virtualMachineScaleSetsClient.PollingDuration = DefaultARMOperationTimeout
|
||||
c.virtualMachineScaleSetVMsClient.PollingDuration = DefaultARMOperationTimeout
|
||||
c.virtualMachinesClient.PollingDuration = DefaultARMOperationTimeout
|
||||
c.availabilitySetsClient.PollingDuration = DefaultARMOperationTimeout
|
||||
|
||||
c.applicationsClient.Authorizer = graphAuthorizer
|
||||
c.servicePrincipalsClient.Authorizer = graphAuthorizer
|
||||
|
|
|
@ -6,10 +6,12 @@ package azurestack
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/Azure/aks-engine/pkg/armhelpers"
|
||||
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2017-03-30/compute"
|
||||
azcompute "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-10-01/compute"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// ListVirtualMachines returns (the first page of) the machines in the specified resource group.
|
||||
|
@ -160,3 +162,36 @@ func (az *AzureClient) SetVirtualMachineScaleSetCapacity(ctx context.Context, re
|
|||
_, err = future.Result(az.virtualMachineScaleSetsClient)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetAvailabilitySet retrieves the specified VM availability set.
|
||||
func (az *AzureClient) GetAvailabilitySet(ctx context.Context, resourceGroup, availabilitySetName string) (azcompute.AvailabilitySet, error) {
|
||||
azVMAS := azcompute.AvailabilitySet{}
|
||||
vmas, err := az.availabilitySetsClient.Get(ctx, resourceGroup, availabilitySetName)
|
||||
if err != nil {
|
||||
log.Printf("fail to get availability set, %v", err)
|
||||
return azVMAS, err
|
||||
}
|
||||
if err = DeepCopy(&azVMAS, vmas); err != nil {
|
||||
log.Printf("fail to convert availability set, %v", err)
|
||||
return azVMAS, err
|
||||
}
|
||||
return azVMAS, nil
|
||||
}
|
||||
|
||||
// GetAvailabilitySetFaultDomainCount returns the first existing fault domain count it finds from the IDs provided.
|
||||
func (az *AzureClient) GetAvailabilitySetFaultDomainCount(ctx context.Context, resourceGroup string, vmasIDs []string) (int, error) {
|
||||
var count int
|
||||
for _, id := range vmasIDs {
|
||||
// extract the last element of the id for VMAS name
|
||||
ss := strings.Split(id, "/")
|
||||
name := ss[len(ss)-1]
|
||||
vmas, err := az.GetAvailabilitySet(ctx, resourceGroup, name)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
// Assume that all VMASes in the cluster share a value for platformFaultDomainCount
|
||||
count = int(*vmas.AvailabilitySetProperties.PlatformFaultDomainCount)
|
||||
break
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
|
|
@ -185,3 +185,66 @@ func TestDeleteVirtualMachine(t *testing.T) {
|
|||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAvailabilitySet(t *testing.T) {
|
||||
mc, err := NewHTTPMockClient()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create HttpMockClient - %s", err)
|
||||
}
|
||||
mc.Activate()
|
||||
defer mc.DeactivateAndReset()
|
||||
mc.RegisterLogin()
|
||||
env := mc.GetEnvironment()
|
||||
|
||||
azureClient, err := NewAzureClientWithClientSecret(env, subscriptionID, "clientID", "secret")
|
||||
if err != nil {
|
||||
t.Fatalf("can not get client %s", err)
|
||||
}
|
||||
|
||||
mc.RegisterGetAvailabilitySet()
|
||||
|
||||
vmas, err := azureClient.GetAvailabilitySet(context.Background(), resourceGroup, virtualMachineAvailabilitySetName)
|
||||
if err != nil {
|
||||
t.Fatalf("can't get availability set: %s", err)
|
||||
}
|
||||
|
||||
var expected int32 = 3
|
||||
if *vmas.PlatformFaultDomainCount != expected {
|
||||
t.Fatalf("expected PlatformFaultDomainCount of %d but got %v", expected, *vmas.PlatformFaultDomainCount)
|
||||
}
|
||||
if *vmas.PlatformUpdateDomainCount != expected {
|
||||
t.Fatalf("expected PlatformUpdateDomainCount of %d but got %v", expected, *vmas.PlatformUpdateDomainCount)
|
||||
}
|
||||
l := "eastus"
|
||||
if *vmas.Location != l {
|
||||
t.Fatalf("expected Location of %s but got %v", l, *vmas.Location)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAvailabilitySetFaultDomainCount(t *testing.T) {
|
||||
mc, err := NewHTTPMockClient()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create HttpMockClient - %s", err)
|
||||
}
|
||||
mc.Activate()
|
||||
defer mc.DeactivateAndReset()
|
||||
mc.RegisterLogin()
|
||||
env := mc.GetEnvironment()
|
||||
|
||||
azureClient, err := NewAzureClientWithClientSecret(env, subscriptionID, "clientID", "secret")
|
||||
if err != nil {
|
||||
t.Fatalf("can not get client %s", err)
|
||||
}
|
||||
|
||||
mc.RegisterGetAvailabilitySetFaultDomainCount()
|
||||
|
||||
count, err := azureClient.GetAvailabilitySetFaultDomainCount(context.Background(), resourceGroup, []string{"id1", "id2"})
|
||||
if err != nil {
|
||||
t.Fatalf("can't get availability set platform fault domain count: %s", err)
|
||||
}
|
||||
|
||||
expected := 3
|
||||
if count != expected {
|
||||
t.Fatalf("platform fault domain count: expected %d but got %d", expected, count)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ const (
|
|||
deploymentName = "testDeplomentName"
|
||||
deploymentStatus = "08586474508192185203"
|
||||
virtualMachineScaleSetName = "vmscalesetName"
|
||||
virtualMachineAvailabilitySetName = "vmavailabilitysetName"
|
||||
virtualMachineName = "testVirtualMachineName"
|
||||
virtualNicName = "testVirtualNicName"
|
||||
virutalDiskName = "testVirtualdickName"
|
||||
|
@ -35,6 +36,7 @@ const (
|
|||
filePathGetVirtualMachine = "httpMockClientData/getVirtualMachine.json"
|
||||
fileDeployVirtualMachine = "httpMockClientData/deployVMResponse.json"
|
||||
fileDeployVirtualMachineError = "httpMockClientData/deploymentVMError.json"
|
||||
filePathGetAvailabilitySet = "httpMockClientData/getAvailabilitySet.json"
|
||||
)
|
||||
|
||||
//HTTPMockClient is an wrapper of httpmock
|
||||
|
@ -60,6 +62,7 @@ type HTTPMockClient struct {
|
|||
ResponseGetVirtualMachine string
|
||||
ResponseDeployVirtualMachine string
|
||||
ResponseDeployVirtualMachineError string
|
||||
ResponseGetAvailabilitySet string
|
||||
}
|
||||
|
||||
//VirtualMachineScaleSetListValues is an wrapper of virtual machine scale set list response values
|
||||
|
@ -125,6 +128,10 @@ func NewHTTPMockClient() (HTTPMockClient, error) {
|
|||
if err != nil {
|
||||
return client, err
|
||||
}
|
||||
client.ResponseGetAvailabilitySet, err = readFromFile(filePathGetAvailabilitySet)
|
||||
if err != nil {
|
||||
return client, err
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
|
||||
|
@ -194,6 +201,26 @@ func (mc HTTPMockClient) RegisterListVirtualMachines() {
|
|||
)
|
||||
}
|
||||
|
||||
// RegisterGetAvailabilitySet registers the mock response for GetAvailabilitySet.
|
||||
func (mc HTTPMockClient) RegisterGetAvailabilitySet() {
|
||||
httpmock.RegisterResponder("GET", fmt.Sprintf("https://management.azure.com/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/availabilitySets/vmavailabilitysetName?api-version=%s", mc.SubscriptionID, mc.ResourceGroup, mc.ComputeAPIVersion),
|
||||
func(req *http.Request) (*http.Response, error) {
|
||||
resp := httpmock.NewStringResponse(200, mc.ResponseGetAvailabilitySet)
|
||||
return resp, nil
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// RegisterGetAvailabilitySetFaultDomainCount registers a mock response for GetAvailabilitySet.
|
||||
func (mc HTTPMockClient) RegisterGetAvailabilitySetFaultDomainCount() {
|
||||
httpmock.RegisterResponder("GET", fmt.Sprintf("https://management.azure.com/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/availabilitySets/id1?api-version=%s", mc.SubscriptionID, mc.ResourceGroup, mc.ComputeAPIVersion),
|
||||
func(req *http.Request) (*http.Response, error) {
|
||||
resp := httpmock.NewStringResponse(200, mc.ResponseGetAvailabilitySet)
|
||||
return resp, nil
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// RegisterGetVirtualMachine registers the mock response for GetVirtualMachine
|
||||
func (mc HTTPMockClient) RegisterGetVirtualMachine() {
|
||||
httpmock.RegisterResponder("GET", fmt.Sprintf("https://management.azure.com/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/virtualMachines/%s?api-version=%s", mc.SubscriptionID, mc.ResourceGroup, mc.VirtualMachineName, mc.ComputeAPIVersion),
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"properties": {
|
||||
"platformUpdateDomainCount": 3,
|
||||
"platformFaultDomainCount": 3,
|
||||
"virtualMachines": [
|
||||
{
|
||||
"id": "/subscriptions/12345678-1234-4fe0-86da-28abc43fc4c7/resourceGroups/MYGROUP/providers/Microsoft.Compute/virtualMachines/K8S-MASTER-26399701-0"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "Microsoft.Compute/availabilitySets",
|
||||
"location": "eastus",
|
||||
"id": "/subscriptions/12345678-1234-4fe0-86da-28abc43fc4c7/resourceGroups/mygroup/providers/Microsoft.Compute/availabilitySets/master-availabilityset-26399701",
|
||||
"name": "master-availabilityset-26399701",
|
||||
"sku": {
|
||||
"name": "Aligned"
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ package armhelpers
|
|||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-10-01/compute"
|
||||
)
|
||||
|
@ -126,3 +127,26 @@ func (az *AzureClient) SetVirtualMachineScaleSetCapacity(ctx context.Context, re
|
|||
_, err = future.Result(az.virtualMachineScaleSetsClient)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetAvailabilitySet retrieves the specified VM availability set.
|
||||
func (az *AzureClient) GetAvailabilitySet(ctx context.Context, resourceGroup, availabilitySetName string) (compute.AvailabilitySet, error) {
|
||||
return az.availabilitySetsClient.Get(ctx, resourceGroup, availabilitySetName)
|
||||
}
|
||||
|
||||
// GetAvailabilitySetFaultDomainCount returns the first existing fault domain count it finds from the IDs provided.
|
||||
func (az *AzureClient) GetAvailabilitySetFaultDomainCount(ctx context.Context, resourceGroup string, vmasIDs []string) (int, error) {
|
||||
var count int
|
||||
for _, id := range vmasIDs {
|
||||
// extract the last element of the id for VMAS name
|
||||
ss := strings.Split(id, "/")
|
||||
name := ss[len(ss)-1]
|
||||
vmas, err := az.GetAvailabilitySet(ctx, resourceGroup, name)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
// Assume that all VMASes in the cluster share a value for platformFaultDomainCount
|
||||
count = int(*vmas.AvailabilitySetProperties.PlatformFaultDomainCount)
|
||||
break
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
|
|
@ -128,6 +128,13 @@ type AKSEngineClient interface {
|
|||
// SetVirtualMachineScaleSetCapacity sets the VMSS capacity
|
||||
SetVirtualMachineScaleSetCapacity(ctx context.Context, resourceGroup, virtualMachineScaleSet string, sku compute.Sku, location string) error
|
||||
|
||||
// GetAvailabilitySet retrieves the specified VM availability set.
|
||||
GetAvailabilitySet(ctx context.Context, resourceGroup, availabilitySet string) (compute.AvailabilitySet, error)
|
||||
|
||||
// GetAvailabilitySetFaultDomainCount returns the first platform fault domain count it finds from the
|
||||
// VM availability set IDs provided.
|
||||
GetAvailabilitySetFaultDomainCount(ctx context.Context, resourceGroup string, vmasIDs []string) (int, error)
|
||||
|
||||
//
|
||||
// STORAGE
|
||||
|
||||
|
|
|
@ -558,7 +558,11 @@ func (mc *MockAKSEngineClient) ListVirtualMachines(ctx context.Context, resource
|
|||
|
||||
if mc.FakeListVirtualMachineResult == nil {
|
||||
mc.FakeListVirtualMachineResult = func() []compute.VirtualMachine {
|
||||
return []compute.VirtualMachine{mc.MakeFakeVirtualMachine(DefaultFakeVMName, defaultK8sVersionForFakeVMs)}
|
||||
machine := mc.MakeFakeVirtualMachine(DefaultFakeVMName, defaultK8sVersionForFakeVMs)
|
||||
machine.AvailabilitySet = &compute.SubResource{
|
||||
ID: to.StringPtr("MockAvailabilitySet"),
|
||||
}
|
||||
return []compute.VirtualMachine{machine}
|
||||
}
|
||||
}
|
||||
vms := mc.FakeListVirtualMachineResult()
|
||||
|
@ -783,6 +787,16 @@ func (mc *MockAKSEngineClient) ListVirtualMachineScaleSetVMs(ctx context.Context
|
|||
}, nil
|
||||
}
|
||||
|
||||
// GetAvailabilitySet mock
|
||||
func (mc *MockAKSEngineClient) GetAvailabilitySet(ctx context.Context, resourceGroup, availabilitySetName string) (compute.AvailabilitySet, error) {
|
||||
return compute.AvailabilitySet{}, nil
|
||||
}
|
||||
|
||||
// GetAvailabilitySetFaultDomainCount mock
|
||||
func (mc *MockAKSEngineClient) GetAvailabilitySetFaultDomainCount(ctx context.Context, resourceGroup string, vmasIDs []string) (int, error) {
|
||||
return 3, nil
|
||||
}
|
||||
|
||||
//GetStorageClient mock
|
||||
func (mc *MockAKSEngineClient) GetStorageClient(ctx context.Context, resourceGroup, accountName string) (AKSStorageClient, error) {
|
||||
if mc.FailGetStorageClient {
|
||||
|
|
|
@ -149,7 +149,6 @@ func TestGenerateARMResourcesWithVMSSAgentPool(t *testing.T) {
|
|||
Name: to.StringPtr("Aligned"),
|
||||
},
|
||||
AvailabilitySetProperties: &compute.AvailabilitySetProperties{
|
||||
PlatformFaultDomainCount: to.Int32Ptr(2),
|
||||
PlatformUpdateDomainCount: to.Int32Ptr(3),
|
||||
},
|
||||
},
|
||||
|
@ -991,7 +990,6 @@ func TestGenerateARMResourceWithVMASAgents(t *testing.T) {
|
|||
AvailabilitySet: compute.AvailabilitySet{
|
||||
AvailabilitySetProperties: &compute.AvailabilitySetProperties{
|
||||
PlatformUpdateDomainCount: to.Int32Ptr(3),
|
||||
PlatformFaultDomainCount: to.Int32Ptr(2),
|
||||
},
|
||||
Sku: &compute.Sku{
|
||||
Name: to.StringPtr("Aligned"),
|
||||
|
|
|
@ -5,6 +5,8 @@ package engine
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/services/cosmos-db/mgmt/2015-04-08/documentdb"
|
||||
"github.com/Azure/azure-sdk-for-go/services/keyvault/mgmt/2018-02-14/keyvault"
|
||||
|
@ -65,6 +67,46 @@ type AvailabilitySetARM struct {
|
|||
compute.AvailabilitySet
|
||||
}
|
||||
|
||||
// MarshalJSON is the custom marshaler for an AvailabilitySetARM.
|
||||
// It acts as a decorator by replacing the JSON field "platformFaultDomainCount"
|
||||
// with an ARM expression if the value was not set.
|
||||
func (a AvailabilitySetARM) MarshalJSON() ([]byte, error) {
|
||||
// alias the type to avoid infinite recursion in marshaling
|
||||
type Alias AvailabilitySetARM
|
||||
bytes, err := json.Marshal((Alias)(a))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if a.AvailabilitySet.PlatformFaultDomainCount != nil {
|
||||
return bytes, nil
|
||||
}
|
||||
|
||||
// armExpr is evaluated by Azure Resource Manager at deployment time:
|
||||
// if location is in the three-fault-domain list, return 3
|
||||
// else if location is "canary" (testing), return 1
|
||||
// else return 2
|
||||
// NOTE: use fault_domains_expr.py to update this ARM expression.
|
||||
armExpr := `"[
|
||||
if( contains(
|
||||
split('canadacentral,centralus,eastus,eastus2,northcentralus,northeurope,southcentralus,westeurope,westus', ','),
|
||||
variables('location') ),
|
||||
3,
|
||||
if( equals('centraluseuap', variables('location') ),
|
||||
1,
|
||||
2
|
||||
))]"`
|
||||
// strip all whitespace
|
||||
armExpr = strings.Join(strings.Fields(armExpr), "")
|
||||
|
||||
// insert ARM expression for platformFaultDomainCount as the first JSON property
|
||||
// NOTE: this relies on this field being omitted in JSON when its value is nil.
|
||||
re := regexp.MustCompile(`"properties" *: *{ *"`)
|
||||
s := re.ReplaceAllLiteralString(string(bytes), `"properties":{"platformFaultDomainCount":`+armExpr+`,"`)
|
||||
|
||||
return []byte(s), nil
|
||||
}
|
||||
|
||||
// StorageAccountARM embeds the ARMResource type in storage.Account.
|
||||
type StorageAccountARM struct {
|
||||
ARMResource
|
||||
|
|
|
@ -9,6 +9,9 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/Azure/aks-engine/pkg/api"
|
||||
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-10-01/compute"
|
||||
"github.com/Azure/go-autorest/autorest/to"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func TestMarshalJSON(t *testing.T) {
|
||||
|
@ -38,6 +41,117 @@ func TestMarshalJSON(t *testing.T) {
|
|||
}
|
||||
armObject := CreateCustomScriptExtension(cs)
|
||||
|
||||
jsonObj, _ := json.MarshalIndent(armObject, "", " ")
|
||||
jsonObj, err := json.MarshalIndent(armObject, "", " ")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
// TODO: why print this? Let's validate it.
|
||||
fmt.Println(string(jsonObj))
|
||||
}
|
||||
|
||||
func TestMarshalJSONAvailabilitySetARM(t *testing.T) {
|
||||
g := NewGomegaWithT(t)
|
||||
|
||||
type VMASTestDatum struct {
|
||||
avSet AvailabilitySetARM
|
||||
json string
|
||||
}
|
||||
|
||||
vmasTestData := []VMASTestDatum{
|
||||
{
|
||||
avSet: AvailabilitySetARM{
|
||||
ARMResource: ARMResource{
|
||||
APIVersion: "[variables('apiVersionCompute')]",
|
||||
},
|
||||
AvailabilitySet: compute.AvailabilitySet{
|
||||
Name: to.StringPtr("[variables('masterAvailabilitySet')]"),
|
||||
Location: to.StringPtr("[variables('location')]"),
|
||||
Type: to.StringPtr("Microsoft.Compute/availabilitySets"),
|
||||
Sku: &compute.Sku{
|
||||
Name: to.StringPtr("Aligned"),
|
||||
},
|
||||
AvailabilitySetProperties: &compute.AvailabilitySetProperties{
|
||||
PlatformFaultDomainCount: to.Int32Ptr(3),
|
||||
PlatformUpdateDomainCount: to.Int32Ptr(3),
|
||||
},
|
||||
},
|
||||
},
|
||||
json: `{
|
||||
"apiVersion": "[variables('apiVersionCompute')]",
|
||||
"properties": {
|
||||
"platformFaultDomainCount": 3,
|
||||
"platformUpdateDomainCount": 3
|
||||
},
|
||||
"sku": {
|
||||
"name": "Aligned"
|
||||
},
|
||||
"name": "[variables('masterAvailabilitySet')]",
|
||||
"type": "Microsoft.Compute/availabilitySets",
|
||||
"location": "[variables('location')]",
|
||||
"tags": null
|
||||
}`},
|
||||
{
|
||||
avSet: AvailabilitySetARM{
|
||||
ARMResource: ARMResource{
|
||||
APIVersion: "[variables('apiVersionCompute')]",
|
||||
},
|
||||
AvailabilitySet: compute.AvailabilitySet{
|
||||
Name: to.StringPtr("[variables('masterAvailabilitySet')]"),
|
||||
Location: to.StringPtr("[variables('location')]"),
|
||||
Type: to.StringPtr("Microsoft.Compute/availabilitySets"),
|
||||
Sku: &compute.Sku{
|
||||
Name: to.StringPtr("Aligned"),
|
||||
},
|
||||
AvailabilitySetProperties: &compute.AvailabilitySetProperties{
|
||||
PlatformUpdateDomainCount: to.Int32Ptr(3),
|
||||
},
|
||||
},
|
||||
},
|
||||
json: `{
|
||||
"apiVersion": "[variables('apiVersionCompute')]",
|
||||
"properties": {
|
||||
"platformFaultDomainCount": "[if(contains(split('canadacentral,centralus,eastus,eastus2,northcentralus,northeurope,southcentralus,westeurope,westus',','),variables('location')),3,if(equals('centraluseuap',variables('location')),1,2))]",
|
||||
"platformUpdateDomainCount": 3
|
||||
},
|
||||
"sku": {
|
||||
"name": "Aligned"
|
||||
},
|
||||
"name": "[variables('masterAvailabilitySet')]",
|
||||
"type": "Microsoft.Compute/availabilitySets",
|
||||
"location": "[variables('location')]",
|
||||
"tags": null
|
||||
}`},
|
||||
{
|
||||
avSet: AvailabilitySetARM{
|
||||
ARMResource: ARMResource{
|
||||
APIVersion: "[variables('apiVersionCompute')]",
|
||||
},
|
||||
AvailabilitySet: compute.AvailabilitySet{
|
||||
Name: to.StringPtr("[variables('masterAvailabilitySet')]"),
|
||||
Location: to.StringPtr("[variables('location')]"),
|
||||
Type: to.StringPtr("Microsoft.Compute/availabilitySets"),
|
||||
Sku: &compute.Sku{
|
||||
Name: to.StringPtr("Aligned"),
|
||||
},
|
||||
AvailabilitySetProperties: &compute.AvailabilitySetProperties{},
|
||||
},
|
||||
},
|
||||
json: `{
|
||||
"apiVersion": "[variables('apiVersionCompute')]",
|
||||
"properties": {},
|
||||
"sku": {
|
||||
"name": "Aligned"
|
||||
},
|
||||
"name": "[variables('masterAvailabilitySet')]",
|
||||
"type": "Microsoft.Compute/availabilitySets",
|
||||
"location": "[variables('location')]",
|
||||
"tags": null
|
||||
}`},
|
||||
}
|
||||
|
||||
for _, vmasTestDatum := range vmasTestData {
|
||||
output, err := json.Marshal(vmasTestDatum.avSet)
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
g.Expect(string(output)).To(MatchJSON(vmasTestDatum.json))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,9 +26,12 @@ func CreateAvailabilitySet(cs *api.ContainerService, isManagedDisks bool) Availa
|
|||
if !cs.Properties.MasterProfile.HasAvailabilityZones() {
|
||||
if isManagedDisks {
|
||||
avSet.AvailabilitySetProperties = &compute.AvailabilitySetProperties{
|
||||
PlatformFaultDomainCount: to.Int32Ptr(2),
|
||||
PlatformUpdateDomainCount: to.Int32Ptr(3),
|
||||
}
|
||||
if cs.Properties.MasterProfile.PlatformFaultDomainCount != nil {
|
||||
p := int32(*cs.Properties.MasterProfile.PlatformFaultDomainCount)
|
||||
avSet.PlatformFaultDomainCount = to.Int32Ptr(p)
|
||||
}
|
||||
avSet.Sku = &compute.Sku{
|
||||
Name: to.StringPtr("Aligned"),
|
||||
}
|
||||
|
@ -57,7 +60,10 @@ func createAgentAvailabilitySets(profile *api.AgentPoolProfile) AvailabilitySetA
|
|||
}
|
||||
|
||||
if profile.IsManagedDisks() {
|
||||
avSet.PlatformFaultDomainCount = to.Int32Ptr(2)
|
||||
if profile.PlatformFaultDomainCount != nil {
|
||||
p := int32(*profile.PlatformFaultDomainCount)
|
||||
avSet.PlatformFaultDomainCount = to.Int32Ptr(p)
|
||||
}
|
||||
avSet.PlatformUpdateDomainCount = to.Int32Ptr(3)
|
||||
avSet.Sku = &compute.Sku{
|
||||
Name: to.StringPtr("Aligned"),
|
||||
|
|
|
@ -65,7 +65,6 @@ func TestCreateAvailabilitySet(t *testing.T) {
|
|||
Name: to.StringPtr("Aligned"),
|
||||
},
|
||||
AvailabilitySetProperties: &compute.AvailabilitySetProperties{
|
||||
PlatformFaultDomainCount: to.Int32Ptr(2),
|
||||
PlatformUpdateDomainCount: to.Int32Ptr(3),
|
||||
},
|
||||
},
|
||||
|
@ -106,6 +105,41 @@ func TestCreateAvailabilitySet(t *testing.T) {
|
|||
t.Errorf("unexpected error while comparing availability sets: %s", diff)
|
||||
}
|
||||
|
||||
// Test availability set with platform fault domain count set
|
||||
count := 3
|
||||
cs = &api.ContainerService{
|
||||
Properties: &api.Properties{
|
||||
MasterProfile: &api.MasterProfile{
|
||||
PlatformFaultDomainCount: &count,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
avSet = CreateAvailabilitySet(cs, true)
|
||||
|
||||
expectedAvSet = AvailabilitySetARM{
|
||||
ARMResource: ARMResource{
|
||||
APIVersion: "[variables('apiVersionCompute')]",
|
||||
},
|
||||
AvailabilitySet: compute.AvailabilitySet{
|
||||
Name: to.StringPtr("[variables('masterAvailabilitySet')]"),
|
||||
Location: to.StringPtr("[variables('location')]"),
|
||||
Type: to.StringPtr("Microsoft.Compute/availabilitySets"),
|
||||
Sku: &compute.Sku{
|
||||
Name: to.StringPtr("Aligned"),
|
||||
},
|
||||
AvailabilitySetProperties: &compute.AvailabilitySetProperties{
|
||||
PlatformFaultDomainCount: to.Int32Ptr(int32(count)),
|
||||
PlatformUpdateDomainCount: to.Int32Ptr(3),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
diff = cmp.Diff(avSet, expectedAvSet)
|
||||
|
||||
if diff != "" {
|
||||
t.Errorf("unexpected error while comparing availability sets: %s", diff)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateAgentAvailabilitySets(t *testing.T) {
|
||||
|
@ -152,7 +186,6 @@ func TestCreateAgentAvailabilitySets(t *testing.T) {
|
|||
Location: to.StringPtr("[variables('location')]"),
|
||||
Type: to.StringPtr("Microsoft.Compute/availabilitySets"),
|
||||
AvailabilitySetProperties: &compute.AvailabilitySetProperties{
|
||||
PlatformFaultDomainCount: to.Int32Ptr(2),
|
||||
PlatformUpdateDomainCount: to.Int32Ptr(3),
|
||||
},
|
||||
Sku: &compute.Sku{
|
||||
|
@ -167,4 +200,37 @@ func TestCreateAgentAvailabilitySets(t *testing.T) {
|
|||
t.Errorf("unexpected error while comparing availability sets: %s", diff)
|
||||
}
|
||||
|
||||
// Test availability set with platform fault domain count set
|
||||
count := 3
|
||||
profile = &api.AgentPoolProfile{
|
||||
Name: "foobar",
|
||||
StorageProfile: api.ManagedDisks,
|
||||
PlatformFaultDomainCount: &count,
|
||||
}
|
||||
|
||||
avSet = createAgentAvailabilitySets(profile)
|
||||
|
||||
expectedAvSet = AvailabilitySetARM{
|
||||
ARMResource: ARMResource{
|
||||
APIVersion: "[variables('apiVersionCompute')]",
|
||||
},
|
||||
AvailabilitySet: compute.AvailabilitySet{
|
||||
Name: to.StringPtr("[variables('foobarAvailabilitySet')]"),
|
||||
Location: to.StringPtr("[variables('location')]"),
|
||||
Type: to.StringPtr("Microsoft.Compute/availabilitySets"),
|
||||
AvailabilitySetProperties: &compute.AvailabilitySetProperties{
|
||||
PlatformFaultDomainCount: to.Int32Ptr(int32(count)),
|
||||
PlatformUpdateDomainCount: to.Int32Ptr(3),
|
||||
},
|
||||
Sku: &compute.Sku{
|
||||
Name: to.StringPtr("Aligned"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
diff = cmp.Diff(avSet, expectedAvSet)
|
||||
|
||||
if diff != "" {
|
||||
t.Errorf("unexpected error while comparing availability sets: %s", diff)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -361,7 +361,6 @@ func TestCreateKubernetesMasterResourcesPVC(t *testing.T) {
|
|||
AvailabilitySet: compute.AvailabilitySet{
|
||||
AvailabilitySetProperties: &compute.AvailabilitySetProperties{
|
||||
PlatformUpdateDomainCount: to.Int32Ptr(3),
|
||||
PlatformFaultDomainCount: to.Int32Ptr(2),
|
||||
},
|
||||
Sku: &compute.Sku{
|
||||
Name: to.StringPtr("Aligned"),
|
||||
|
|
|
@ -244,6 +244,8 @@ func (uc *UpgradeCluster) getClusterNodeStatus(kubeClient armhelpers.KubernetesC
|
|||
}
|
||||
}
|
||||
|
||||
availabilitySetIDs := []string{}
|
||||
|
||||
for vmListPage, err := uc.Client.ListVirtualMachines(ctx, resourceGroup); vmListPage.NotDone(); err = vmListPage.Next() {
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -258,6 +260,10 @@ func (uc *UpgradeCluster) getClusterNodeStatus(kubeClient armhelpers.KubernetesC
|
|||
}
|
||||
currentVersion := uc.getNodeVersion(kubeClient, strings.ToLower(*vm.Name), vm.Tags, true)
|
||||
|
||||
if vm.AvailabilitySet != nil {
|
||||
availabilitySetIDs = append(availabilitySetIDs, *vm.AvailabilitySet.ID)
|
||||
}
|
||||
|
||||
if uc.Force {
|
||||
if currentVersion == "" {
|
||||
currentVersion = "Unknown"
|
||||
|
@ -283,6 +289,13 @@ func (uc *UpgradeCluster) getClusterNodeStatus(kubeClient armhelpers.KubernetesC
|
|||
}
|
||||
}
|
||||
|
||||
// set the VMAS platformFaultDomainCount to match the existing value
|
||||
fdCount, err := uc.Client.GetAvailabilitySetFaultDomainCount(ctx, resourceGroup, availabilitySetIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
uc.DataModel.SetPlatformFaultDomainCount(fdCount)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -614,6 +614,32 @@ var _ = Describe("Upgrade Kubernetes cluster tests", func() {
|
|||
Expect(*uc.MasterVMs).To(HaveLen(1))
|
||||
Expect(*uc.UpgradedMasterVMs).To(HaveLen(0))
|
||||
})
|
||||
It("Should set platform fault domain count based on availability sets", func() {
|
||||
cs := api.CreateMockContainerService("testcluster", "1.9.11", 3, 2, false)
|
||||
cs.Properties.OrchestratorProfile.KubernetesConfig = &api.KubernetesConfig{}
|
||||
cs.Properties.OrchestratorProfile.KubernetesConfig.UseManagedIdentity = true
|
||||
uc := UpgradeCluster{
|
||||
Translator: &i18n.Translator{},
|
||||
Logger: log.NewEntry(log.New()),
|
||||
}
|
||||
|
||||
mockClient := armhelpers.MockAKSEngineClient{}
|
||||
uc.Client = &mockClient
|
||||
|
||||
uc.ClusterTopology = ClusterTopology{}
|
||||
uc.SubscriptionID = "DEC923E3-1EF1-4745-9516-37906D56DEC4"
|
||||
uc.ResourceGroup = "TestRg"
|
||||
uc.DataModel = cs
|
||||
uc.NameSuffix = "12345678"
|
||||
uc.AgentPoolsToUpgrade = map[string]bool{"agentpool1": true}
|
||||
|
||||
err := uc.UpgradeCluster(&mockClient, "kubeConfig", TestAKSEngineVersion)
|
||||
Expect(err).To(BeNil())
|
||||
Expect(*cs.Properties.MasterProfile.PlatformFaultDomainCount).To(Equal(3))
|
||||
for _, pool := range cs.Properties.AgentPoolProfiles {
|
||||
Expect(*pool.PlatformFaultDomainCount).To(Equal(3))
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
It("Should not fail if no managed identity is returned by azure during upgrade operation", func() {
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Generates an Azure Resource Manager (ARM) expression that will evaluate at
|
||||
deployment time to the number of fault domains available in a given location.
|
||||
Also generates Go code referencing the expression.
|
||||
|
||||
Since there is no API to query the fault domain count for an Azure location,
|
||||
this script parses the public documentation to find out.
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import textwrap
|
||||
import urllib.request
|
||||
|
||||
|
||||
ARM_EXPR = """\
|
||||
"[
|
||||
if( contains(
|
||||
split('{}', ','),
|
||||
variables('location') ),
|
||||
3,
|
||||
if( equals('centraluseuap', variables('location') ),
|
||||
1,
|
||||
2
|
||||
))]"\
|
||||
"""
|
||||
|
||||
GO_CODE = """\
|
||||
// armExpr is evaluated by Azure Resource Manager at deployment time:
|
||||
// if location is in the three-fault-domain list, return 3
|
||||
// else if location is "canary" (testing), return 1
|
||||
// else return 2
|
||||
// NOTE: use {} to update this ARM expression.
|
||||
armExpr := `{}`
|
||||
// strip all whitespace
|
||||
armExpr = strings.Join(strings.Fields(armExpr), "")
|
||||
""".format(os.path.basename(__file__), ARM_EXPR)
|
||||
|
||||
SOURCE_DOC = 'https://raw.githubusercontent.com/MicrosoftDocs/azure-docs/master/includes/managed-disks-common-fault-domain-region-list.md' # pylint: disable=line-too-long
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
Print an ARM expression that returns the fault domain count for an Azure
|
||||
location, as well as the associated Go code, ready for copy-and-paste.
|
||||
"""
|
||||
regex = re.compile(r"""
|
||||
\|\s* # vertical bar followed by whitespace
|
||||
([A-Za-z0-9 ]*?) # >= 0 location name characters (lazy, capture)
|
||||
\s+\|\s* # >= 1 whitespace chars, vertical bar, more whitespace
|
||||
(\d) # a single digit (capture)
|
||||
\s*\| # whitespace followed by a vertical bar
|
||||
""", re.VERBOSE)
|
||||
|
||||
markdown = urllib.request.urlopen(SOURCE_DOC).read().decode("utf8")
|
||||
# Since the canary region is hard-coded, only the regions with three
|
||||
# fault domains need to be included in the expression.
|
||||
threes = (m[0].replace(' ', '').lower() for m in regex.findall(markdown)
|
||||
if int(m[1]) == 3)
|
||||
threes = ','.join(sorted(threes))
|
||||
|
||||
print("\n\033[1;36mARM expression minified:\033[0;0m \n")
|
||||
print("".join(ARM_EXPR.format(threes).split()))
|
||||
print("\n\033[1;34mGo code snippet:\033[0;0m \n")
|
||||
print(textwrap.indent(GO_CODE.format(threes), "\t"))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Загрузка…
Ссылка в новой задаче