diff --git a/pkg/cloudprovider/providers/azure/azure.go b/pkg/cloudprovider/providers/azure/azure.go index 62da8dc27e..49ca15bff3 100644 --- a/pkg/cloudprovider/providers/azure/azure.go +++ b/pkg/cloudprovider/providers/azure/azure.go @@ -423,6 +423,9 @@ func parseConfig(configReader io.Reader) (*Config, error) { return nil, err } + // The resource group name may be in different cases from different Azure APIs, hence it is converted to lower here. + // See more context at https://github.com/kubernetes/kubernetes/issues/71994. + config.ResourceGroup = strings.ToLower(config.ResourceGroup) return &config, nil } @@ -578,7 +581,7 @@ func (az *Cloud) updateNodeCaches(prevNode, newNode *v1.Node) { // Add to nodeResourceGroups cache. newRG, ok := newNode.ObjectMeta.Labels[externalResourceGroupLabel] if ok && len(newRG) > 0 { - az.nodeResourceGroups[newNode.ObjectMeta.Name] = newRG + az.nodeResourceGroups[newNode.ObjectMeta.Name] = strings.ToLower(newRG) } // Add to unmanagedNodes cache. @@ -677,7 +680,7 @@ func (az *Cloud) GetUnmanagedNodes() (sets.String, error) { // ShouldNodeExcludedFromLoadBalancer returns true if node is unmanaged or in external resource group. func (az *Cloud) ShouldNodeExcludedFromLoadBalancer(node *v1.Node) bool { labels := node.ObjectMeta.Labels - if rg, ok := labels[externalResourceGroupLabel]; ok && rg != az.ResourceGroup { + if rg, ok := labels[externalResourceGroupLabel]; ok && !strings.EqualFold(rg, az.ResourceGroup) { return true } diff --git a/pkg/cloudprovider/providers/azure/azure_instances.go b/pkg/cloudprovider/providers/azure/azure_instances.go index 87acadfd59..07bba979b7 100644 --- a/pkg/cloudprovider/providers/azure/azure_instances.go +++ b/pkg/cloudprovider/providers/azure/azure_instances.go @@ -246,7 +246,7 @@ func (az *Cloud) InstanceID(ctx context.Context, name types.NodeName) (string, e } // Get resource group name. - resourceGroup := metadata.Compute.ResourceGroup + resourceGroup := strings.ToLower(metadata.Compute.ResourceGroup) // Compose instanceID based on nodeName for standard instance. if az.VMType == vmTypeStandard { diff --git a/pkg/cloudprovider/providers/azure/azure_metrics.go b/pkg/cloudprovider/providers/azure/azure_metrics.go index cae35c594b..c0806250b9 100644 --- a/pkg/cloudprovider/providers/azure/azure_metrics.go +++ b/pkg/cloudprovider/providers/azure/azure_metrics.go @@ -17,6 +17,7 @@ limitations under the License. package azure import ( + "strings" "time" "github.com/prometheus/client_golang/prometheus" @@ -45,7 +46,7 @@ type metricContext struct { func newMetricContext(prefix, request, resourceGroup, subscriptionID string) *metricContext { return &metricContext{ start: time.Now(), - attributes: []string{prefix + "_" + request, resourceGroup, subscriptionID}, + attributes: []string{prefix + "_" + request, strings.ToLower(resourceGroup), subscriptionID}, } } diff --git a/pkg/cloudprovider/providers/azure/azure_standard.go b/pkg/cloudprovider/providers/azure/azure_standard.go index 29568b2e2a..4746e0fe1d 100644 --- a/pkg/cloudprovider/providers/azure/azure_standard.go +++ b/pkg/cloudprovider/providers/azure/azure_standard.go @@ -70,7 +70,7 @@ func (az *Cloud) getStandardMachineID(resourceGroup, machineName string) string return fmt.Sprintf( machineIDTemplate, az.SubscriptionID, - resourceGroup, + strings.ToLower(resourceGroup), machineName) } @@ -339,7 +339,14 @@ func (as *availabilitySet) GetInstanceIDByNodeName(name string) (string, error) return "", err } } - return *machine.ID, nil + + resourceID := *machine.ID + convertedResourceID, err := convertResourceGroupNameToLower(resourceID) + if err != nil { + klog.Errorf("convertResourceGroupNameToLower failed with error: %v", err) + return "", err + } + return convertedResourceID, nil } // GetPowerStatusByNodeName returns the power state of the specified node. diff --git a/pkg/cloudprovider/providers/azure/azure_test.go b/pkg/cloudprovider/providers/azure/azure_test.go index 7400a9fd47..003a89765d 100644 --- a/pkg/cloudprovider/providers/azure/azure_test.go +++ b/pkg/cloudprovider/providers/azure/azure_test.go @@ -99,7 +99,7 @@ func TestParseConfig(t *testing.T) { MaximumLoadBalancerRuleCount: 1, PrimaryAvailabilitySetName: "primaryAvailabilitySetName", PrimaryScaleSetName: "primaryScaleSetName", - ResourceGroup: "resourceGroup", + ResourceGroup: "resourcegroup", RouteTableName: "routeTableName", SecurityGroupName: "securityGroupName", SubnetName: "subnetName", diff --git a/pkg/cloudprovider/providers/azure/azure_vmss.go b/pkg/cloudprovider/providers/azure/azure_vmss.go index 26d1bd9d1a..a2ef73b3a9 100644 --- a/pkg/cloudprovider/providers/azure/azure_vmss.go +++ b/pkg/cloudprovider/providers/azure/azure_vmss.go @@ -185,7 +185,13 @@ func (ss *scaleSet) GetInstanceIDByNodeName(name string) (string, error) { return "", err } - return *vm.ID, nil + resourceID := *vm.ID + convertedResourceID, err := convertResourceGroupNameToLower(resourceID) + if err != nil { + klog.Errorf("convertResourceGroupNameToLower failed with error: %v", err) + return "", err + } + return convertedResourceID, nil } // GetNodeNameByProviderID gets the node name by provider ID. @@ -980,7 +986,7 @@ func (az *Cloud) getVmssMachineID(resourceGroup, scaleSetName, instanceID string return fmt.Sprintf( vmssMachineIDTemplate, az.SubscriptionID, - resourceGroup, + strings.ToLower(resourceGroup), scaleSetName, instanceID) } diff --git a/pkg/cloudprovider/providers/azure/azure_vmss_cache.go b/pkg/cloudprovider/providers/azure/azure_vmss_cache.go index 07d30b7885..ee1fb1c64c 100644 --- a/pkg/cloudprovider/providers/azure/azure_vmss_cache.go +++ b/pkg/cloudprovider/providers/azure/azure_vmss_cache.go @@ -152,7 +152,7 @@ func (ss *scaleSet) newAvailabilitySetNodesCache() (*timedCache, error) { func buildVmssCacheKey(resourceGroup, name string) string { // key is composed of # - return fmt.Sprintf("%s%s%s", resourceGroup, vmssCacheSeparator, name) + return fmt.Sprintf("%s%s%s", strings.ToLower(resourceGroup), vmssCacheSeparator, name) } func extractVmssCacheKey(key string) (string, string, error) { diff --git a/pkg/cloudprovider/providers/azure/azure_wrap.go b/pkg/cloudprovider/providers/azure/azure_wrap.go index cf3632956a..95e8c7dac8 100644 --- a/pkg/cloudprovider/providers/azure/azure_wrap.go +++ b/pkg/cloudprovider/providers/azure/azure_wrap.go @@ -37,7 +37,8 @@ var ( nsgCacheTTL = 2 * time.Minute rtCacheTTL = 2 * time.Minute - azureNodeProviderIDRE = regexp.MustCompile(`^azure:///subscriptions/(?:.*)/resourceGroups/(?:.*)/providers/Microsoft.Compute/(?:.*)`) + azureNodeProviderIDRE = regexp.MustCompile(`^azure:///subscriptions/(?:.*)/resourceGroups/(?:.*)/providers/Microsoft.Compute/(?:.*)`) + azureResourceGroupNameRE = regexp.MustCompile(`.*/subscriptions/(?:.*)/resourceGroups/(.+)/providers/(?:.*)`) ) // checkExistsFromError inspects an error and returns a true if err is nil, @@ -303,3 +304,14 @@ func (az *Cloud) IsNodeUnmanaged(nodeName string) (bool, error) { func (az *Cloud) IsNodeUnmanagedByProviderID(providerID string) bool { return !azureNodeProviderIDRE.Match([]byte(providerID)) } + +// convertResourceGroupNameToLower converts the resource group name in the resource ID to be lowered. +func convertResourceGroupNameToLower(resourceID string) (string, error) { + matches := azureResourceGroupNameRE.FindStringSubmatch(resourceID) + if len(matches) != 2 { + return "", fmt.Errorf("%q isn't in Azure resource ID format %q", resourceID, azureResourceGroupNameRE.String()) + } + + resourceGroup := matches[1] + return strings.Replace(resourceID, resourceGroup, strings.ToLower(resourceGroup), 1), nil +} diff --git a/pkg/cloudprovider/providers/azure/azure_wrap_test.go b/pkg/cloudprovider/providers/azure/azure_wrap_test.go index 3ac2bfc6b5..84367b547c 100644 --- a/pkg/cloudprovider/providers/azure/azure_wrap_test.go +++ b/pkg/cloudprovider/providers/azure/azure_wrap_test.go @@ -142,3 +142,59 @@ func TestIsNodeUnmanagedByProviderID(t *testing.T) { assert.Equal(t, test.expected, isUnmanagedNode, test.providerID) } } + +func TestConvertResourceGroupNameToLower(t *testing.T) { + tests := []struct { + desc string + resourceID string + expected string + expectError bool + }{ + { + desc: "empty string should report error", + resourceID: "", + expectError: true, + }, + { + desc: "resourceID not in Azure format should report error", + resourceID: "invalid-id", + expectError: true, + }, + { + desc: "providerID not in Azure format should report error", + resourceID: "azure://invalid-id", + expectError: true, + }, + { + desc: "resource group name in VM providerID should be converted", + resourceID: CloudProviderName + ":///subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myResourceGroupName/providers/Microsoft.Compute/virtualMachines/k8s-agent-AAAAAAAA-0", + expected: CloudProviderName + ":///subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myresourcegroupname/providers/Microsoft.Compute/virtualMachines/k8s-agent-AAAAAAAA-0", + }, + { + desc: "resource group name in VM resourceID should be converted", + resourceID: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myResourceGroupName/providers/Microsoft.Compute/virtualMachines/k8s-agent-AAAAAAAA-0", + expected: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myresourcegroupname/providers/Microsoft.Compute/virtualMachines/k8s-agent-AAAAAAAA-0", + }, + { + desc: "resource group name in VMSS providerID should be converted", + resourceID: CloudProviderName + ":///subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myResourceGroupName/providers/Microsoft.Compute/virtualMachineScaleSets/myScaleSetName/virtualMachines/156", + expected: CloudProviderName + ":///subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myresourcegroupname/providers/Microsoft.Compute/virtualMachineScaleSets/myScaleSetName/virtualMachines/156", + }, + { + desc: "resource group name in VMSS resourceID should be converted", + resourceID: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myResourceGroupName/providers/Microsoft.Compute/virtualMachineScaleSets/myScaleSetName/virtualMachines/156", + expected: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myresourcegroupname/providers/Microsoft.Compute/virtualMachineScaleSets/myScaleSetName/virtualMachines/156", + }, + } + + for _, test := range tests { + real, err := convertResourceGroupNameToLower(test.resourceID) + if test.expectError { + assert.NotNil(t, err, test.desc) + continue + } + + assert.Nil(t, err, test.desc) + assert.Equal(t, test.expected, real, test.desc) + } +}