Skip to content

Commit

Permalink
fetch acr login server and storage suffix from env/resourcemanager
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinForReal committed Dec 11, 2024
1 parent b23629d commit fc0fcea
Show file tree
Hide file tree
Showing 6 changed files with 189 additions and 174 deletions.
6 changes: 5 additions & 1 deletion pkg/azclient/arm_conf.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ type ARMClientConfig struct {
CloudProviderBackoffRetries int32 `json:"cloudProviderBackoffRetries,omitempty" yaml:"cloudProviderBackoffRetries,omitempty"`
// Backoff duration
CloudProviderBackoffDuration int `json:"cloudProviderBackoffDuration,omitempty" yaml:"cloudProviderBackoffDuration,omitempty"`
//Storage suffix
StorageSuffix *string `json:"storageSuffix,omitempty" yaml:"storageSuffix,omitempty"`
//ACRLoginServer
ACRLoginServer *string `json:"acrLoginServer,omitempty" yaml:"containerRegistrySuffix,omitempty"`
}

func (config *ARMClientConfig) GetTenantID() string {
Expand All @@ -65,7 +69,7 @@ func GetAzCoreClientOption(armConfig *ARMClientConfig) (*policy.ClientOptions, e
azCoreClientConfig.PerCallPolicies = append(azCoreClientConfig.PerCallPolicies, useragent.NewCustomUserAgentPolicy(userAgent))
}
//set cloud
cloudConfig, err := GetAzureCloudConfig(armConfig)
cloudConfig, err := GetAzureCloudConfigAndBackfillARMClientConfig(armConfig)
if err != nil {
return nil, err
}
Expand Down
1 change: 1 addition & 0 deletions pkg/azclient/backendaddresspoolclient/custom_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ func init() {
_, err = pollerResp.PollUntilDone(ctx, nil)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
pippollerResp, err := publicIPClient.BeginDelete(ctx, resourceGroupName, publicIPName, nil)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
_, err = pippollerResp.PollUntilDone(ctx, nil)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
}
Expand Down
12 changes: 6 additions & 6 deletions pkg/azclient/client-gen/generator/clientfactory.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ var AbstractClientFactoryImplTemplate = template.Must(template.New("object-facto
`
type ClientFactoryImpl struct {
armConfig *ARMClientConfig
facotryConfig *ClientFactoryConfig
factoryConfig *ClientFactoryConfig
cred azcore.TokenCredential
clientOptionsMutFn []func(option *arm.ClientOptions)
{{range $key, $client := . -}}
Expand All @@ -211,7 +211,7 @@ func NewClientFactory(config *ClientFactoryConfig, armConfig *ARMClientConfig, c
factory := &ClientFactoryImpl{
armConfig: armConfig,
facotryConfig: config,
factoryConfig: config,
cred: cred,
clientOptionsMutFn: clientOptionsMutFn,
}
Expand Down Expand Up @@ -240,7 +240,7 @@ func NewClientFactory(config *ClientFactoryConfig, armConfig *ARMClientConfig, c
{{- end }}
func (factory *ClientFactoryImpl) create{{$resource}}Client(subscription string)({{.PkgAlias}}.{{.InterfaceTypeName}},error) {
//initialize {{.PkgAlias}}
options, err := GetDefaultResourceClientOption(factory.armConfig, factory.facotryConfig)
options, err := GetDefaultResourceClientOption(factory.armConfig, factory.factoryConfig)
if err != nil {
return nil, err
}
Expand All @@ -251,7 +251,7 @@ func (factory *ClientFactoryImpl) create{{$resource}}Client(subscription string)
{{- end }}
{{with $client.RateLimitKey}}
//add ratelimit policy
ratelimitOption := factory.facotryConfig.GetRateLimitConfig("{{.}}")
ratelimitOption := factory.factoryConfig.GetRateLimitConfig("{{.}}")
rateLimitPolicy := ratelimit.NewRateLimitPolicy(ratelimitOption)
if rateLimitPolicy != nil {
options.ClientOptions.PerCallPolicies = append(options.ClientOptions.PerCallPolicies, rateLimitPolicy)
Expand All @@ -266,12 +266,12 @@ func (factory *ClientFactoryImpl) create{{$resource}}Client(subscription string)
}
{{ if $client.CrossSubFactory }}
func (factory *ClientFactoryImpl) Get{{$resource}}Client(){{.PkgAlias}}.{{.InterfaceTypeName}} {
clientImp,_:= factory.{{ $key }}.Load(strings.ToLower(factory.facotryConfig.SubscriptionID))
clientImp,_:= factory.{{ $key }}.Load(strings.ToLower(factory.factoryConfig.SubscriptionID))
return clientImp.({{.PkgAlias}}.{{.InterfaceTypeName}})
}
func (factory *ClientFactoryImpl) Get{{$resource}}ClientForSub(subscriptionID string)({{.PkgAlias}}.{{.InterfaceTypeName}},error) {
if subscriptionID == "" {
subscriptionID = factory.facotryConfig.SubscriptionID
subscriptionID = factory.factoryConfig.SubscriptionID
}
clientImp,loaded:= factory.{{ $key }}.Load(strings.ToLower(subscriptionID))
if loaded {
Expand Down
166 changes: 81 additions & 85 deletions pkg/azclient/cloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,67 +52,80 @@ func AzureCloudConfigFromName(cloudName string) *cloud.Configuration {
return nil
}

// AzureCloudConfigFromURL returns cloud config from url
// OverrideAzureCloudConfigFromMetadataService returns cloud config from url
// track2 sdk will add this one in the near future https://github.com/Azure/azure-sdk-for-go/issues/20959
func AzureCloudConfigFromURL(endpoint string) (*cloud.Configuration, error) {
managementEndpoint := fmt.Sprintf("%s%s", strings.TrimSuffix(endpoint, "/"), "/metadata/endpoints?api-version=2019-05-01")
func OverrideAzureCloudConfigFromMetadataService(armconfig *ARMClientConfig, config *cloud.Configuration) error {
if armconfig == nil || armconfig.ResourceManagerEndpoint == "" {
return nil
}

managementEndpoint := fmt.Sprintf("%s%s", strings.TrimSuffix(armconfig.ResourceManagerEndpoint, "/"), "/metadata/endpoints?api-version=2019-05-01")
res, err := http.Get(managementEndpoint) //nolint
if err != nil {
return nil, err
return err
}
body, err := io.ReadAll(res.Body)
if err != nil {
return nil, err
return err
}
metadata := []struct {
Authentication struct {
Audiences []string
LoginEndpoint string
}
Name, ResourceManager string
Name string `json:"name"`
ResourceManager string `json:"resourceManager,omitempty"`
Authentication struct {
Audiences []string `json:"audiences"`
LoginEndpoint string `json:"loginEndpoint,omitempty"`
} `json:"authentication"`
Suffixes struct {
AcrLoginServer *string `json:"acrLoginServer,omitempty"`
Storage *string `json:"storage,omitempty"`
} `json:"suffixes,omitempty"`
}{}
err = json.Unmarshal(body, &metadata)
if err != nil {
return nil, err
return err
}

if len(metadata) > 0 {
// We use the endpoint to build our config, but on ASH the config returned
// does not contain the endpoint, and this is not accounted for. This
// ultimately unsets it for the returned config, causing the bootstrap of
// the provider to fail. Instead, check if the endpoint is returned, and if
// It is not then set it.
if len(metadata[0].ResourceManager) == 0 {
metadata[0].ResourceManager = endpoint
for _, item := range metadata {
if armconfig.Cloud == "" || strings.EqualFold(item.Name, armconfig.Cloud) {
// We use the endpoint to build our config, but on ASH the config returned
// does not contain the endpoint, and this is not accounted for. This
// ultimately unsets it for the returned config, causing the bootstrap of
// the provider to fail. Instead, check if the endpoint is returned, and if
// It is not then set it.
if item.ResourceManager == "" {
item.ResourceManager = armconfig.ResourceManagerEndpoint
}
config.Services[cloud.ResourceManager] = cloud.ServiceConfiguration{
Endpoint: item.ResourceManager,
Audience: item.Authentication.Audiences[0],
}
if item.Authentication.LoginEndpoint != "" {
config.ActiveDirectoryAuthorityHost = item.Authentication.LoginEndpoint
}
if item.Suffixes.Storage != nil && armconfig.StorageSuffix == nil {
armconfig.StorageSuffix = item.Suffixes.Storage
}
if item.Suffixes.AcrLoginServer != nil && armconfig.ACRLoginServer == nil {
armconfig.ACRLoginServer = item.Suffixes.AcrLoginServer
}
return nil
}
return &cloud.Configuration{
ActiveDirectoryAuthorityHost: metadata[0].Authentication.LoginEndpoint,
Services: map[cloud.ServiceName]cloud.ServiceConfiguration{
cloud.ResourceManager: {
Endpoint: metadata[0].ResourceManager,
Audience: metadata[0].Authentication.Audiences[0],
},
},
}, nil
}
return nil, nil
}
return nil
}

func AzureCloudConfigOverrideFromEnv(config *cloud.Configuration) (*cloud.Configuration, error) {
if config == nil {
config = &cloud.AzurePublic
}
func OverrideAzureCloudConfigFromEnv(armconfig *ARMClientConfig, config *cloud.Configuration) error {
envFilePath, ok := os.LookupEnv(EnvironmentFilepathName)
if !ok {
return config, nil
return nil
}
content, err := os.ReadFile(envFilePath)
if err != nil {
return nil, err
return err
}
var envConfig Environment
if err = json.Unmarshal(content, &envConfig); err != nil {
return nil, err
return err
}
if len(envConfig.ActiveDirectoryEndpoint) > 0 {
config.ActiveDirectoryAuthorityHost = envConfig.ActiveDirectoryEndpoint
Expand All @@ -123,61 +136,44 @@ func AzureCloudConfigOverrideFromEnv(config *cloud.Configuration) (*cloud.Config
Audience: envConfig.TokenAudience,
}
}
return config, nil
if len(envConfig.StorageEndpointSuffix) > 0 {
armconfig.StorageSuffix = &envConfig.StorageEndpointSuffix
}
if len(envConfig.ContainerRegistryDNSSuffix) > 0 {
armconfig.ACRLoginServer = &envConfig.ContainerRegistryDNSSuffix
}
return nil
}

// GetAzureCloudConfig returns the cloud configuration for the given ARMClientConfig.
func GetAzureCloudConfig(armConfig *ARMClientConfig) (*cloud.Configuration, error) {
// GetAzureCloudConfigAndBackfillArmClientConfig retrieves the Azure cloud configuration based on the provided ARM client configuration.
// If the ARM client configuration is nil, it returns the default Azure public cloud configuration.
// It attempts to override the cloud configuration using metadata service and environment variables.
//
// Parameters:
// - armConfig: A pointer to an ARMClientConfig struct containing the ARM client configuration.
//
// Returns:
// - A pointer to a cloud.Configuration struct representing the Azure cloud configuration.
// - An error if there is an issue overriding the cloud configuration from metadata service or environment variables.
func GetAzureCloudConfigAndBackfillARMClientConfig(armConfig *ARMClientConfig) (*cloud.Configuration, error) {
config := &cloud.AzurePublic
if armConfig == nil {
return &cloud.AzurePublic, nil
return config, nil
}
if armConfig.ResourceManagerEndpoint != "" {
return AzureCloudConfigFromURL(armConfig.ResourceManagerEndpoint)
config = AzureCloudConfigFromName(armConfig.Cloud)
if err := OverrideAzureCloudConfigFromMetadataService(armConfig, config); err != nil {
return nil, err
}

return AzureCloudConfigOverrideFromEnv(AzureCloudConfigFromName(armConfig.Cloud))
err := OverrideAzureCloudConfigFromEnv(armConfig, config)
return config, err
}

// Environment represents a set of endpoints for each of Azure's Clouds.
type Environment struct {
Name string `json:"name"`
ManagementPortalURL string `json:"managementPortalURL"`
PublishSettingsURL string `json:"publishSettingsURL"`
ServiceManagementEndpoint string `json:"serviceManagementEndpoint"`
ResourceManagerEndpoint string `json:"resourceManagerEndpoint"`
ActiveDirectoryEndpoint string `json:"activeDirectoryEndpoint"`
GalleryEndpoint string `json:"galleryEndpoint"`
KeyVaultEndpoint string `json:"keyVaultEndpoint"`
ManagedHSMEndpoint string `json:"managedHSMEndpoint"`
GraphEndpoint string `json:"graphEndpoint"`
ServiceBusEndpoint string `json:"serviceBusEndpoint"`
BatchManagementEndpoint string `json:"batchManagementEndpoint"`
MicrosoftGraphEndpoint string `json:"microsoftGraphEndpoint"`
StorageEndpointSuffix string `json:"storageEndpointSuffix"`
CosmosDBDNSSuffix string `json:"cosmosDBDNSSuffix"`
MariaDBDNSSuffix string `json:"mariaDBDNSSuffix"`
MySQLDatabaseDNSSuffix string `json:"mySqlDatabaseDNSSuffix"`
PostgresqlDatabaseDNSSuffix string `json:"postgresqlDatabaseDNSSuffix"`
SQLDatabaseDNSSuffix string `json:"sqlDatabaseDNSSuffix"`
TrafficManagerDNSSuffix string `json:"trafficManagerDNSSuffix"`
KeyVaultDNSSuffix string `json:"keyVaultDNSSuffix"`
ManagedHSMDNSSuffix string `json:"managedHSMDNSSuffix"`
ServiceBusEndpointSuffix string `json:"serviceBusEndpointSuffix"`
ServiceManagementVMDNSSuffix string `json:"serviceManagementVMDNSSuffix"`
ResourceManagerVMDNSSuffix string `json:"resourceManagerVMDNSSuffix"`
ContainerRegistryDNSSuffix string `json:"containerRegistryDNSSuffix"`
TokenAudience string `json:"tokenAudience"`
APIManagementHostNameSuffix string `json:"apiManagementHostNameSuffix"`
SynapseEndpointSuffix string `json:"synapseEndpointSuffix"`
DatalakeSuffix string `json:"datalakeSuffix"`
ResourceIdentifiers ResourceIdentifier `json:"resourceIdentifiers"`
}

// ResourceIdentifier contains a set of Azure resource IDs.
type ResourceIdentifier struct {
Graph string `json:"graph"`
KeyVault string `json:"keyVault"`
Datalake string `json:"datalake"`
Batch string `json:"batch"`
OperationalInsights string `json:"operationalInsights"`
Name string `json:"name"`
ResourceManagerEndpoint string `json:"resourceManagerEndpoint"`
ActiveDirectoryEndpoint string `json:"activeDirectoryEndpoint"`
StorageEndpointSuffix string `json:"storageEndpointSuffix"`
ContainerRegistryDNSSuffix string `json:"containerRegistryDNSSuffix"`
TokenAudience string `json:"tokenAudience"`
}
34 changes: 24 additions & 10 deletions pkg/azclient/cloud_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,9 @@ var _ = ginkgo.Describe("Cloud", func() {
gomega.Expect(err).ToNot(gomega.HaveOccurred())
}))
defer server.Close()

cloudConfig, err := azclient.AzureCloudConfigFromURL(server.URL)
armconfig := &azclient.ARMClientConfig{}
cloudConfig := &cloud.AzurePublic
err := azclient.OverrideAzureCloudConfigFromMetadataService(armconfig, cloudConfig)
gomega.Expect(err).ToNot(gomega.HaveOccurred())
gomega.Expect(cloudConfig).ToNot(gomega.BeNil())
gomega.Expect(cloudConfig.ActiveDirectoryAuthorityHost).To(gomega.Equal("https://login.microsoftonline.com/"))
Expand Down Expand Up @@ -129,8 +130,13 @@ var _ = ginkgo.Describe("Cloud", func() {
gomega.Expect(err).ToNot(gomega.HaveOccurred())
}))
defer server.Close()

cloudConfig, err := azclient.AzureCloudConfigFromURL(server.URL)
armconfig := &azclient.ARMClientConfig{
ResourceManagerEndpoint: server.URL,
}
cloudConfig := &cloud.Configuration{
ActiveDirectoryAuthorityHost: "https://login.microsoftonline.com/", Services: map[cloud.ServiceName]cloud.ServiceConfiguration{},
}
err := azclient.OverrideAzureCloudConfigFromMetadataService(armconfig, cloudConfig)
gomega.Expect(err).ToNot(gomega.HaveOccurred())
gomega.Expect(cloudConfig).ToNot(gomega.BeNil())
gomega.Expect(cloudConfig.ActiveDirectoryAuthorityHost).To(gomega.Equal("https://login.microsoftonline.com/"))
Expand Down Expand Up @@ -170,7 +176,9 @@ var _ = ginkgo.Describe("Cloud", func() {
ginkgo.Context("AzureCloudFromEnvironment", func() {
ginkgo.When("the environment is empty", func() {
ginkgo.It("should return the default cloud", func() {
cloudConfig, err := azclient.AzureCloudConfigOverrideFromEnv(nil)
armconfig := &azclient.ARMClientConfig{}
cloudConfig := &cloud.AzurePublic
err := azclient.OverrideAzureCloudConfigFromEnv(armconfig, cloudConfig)
gomega.Expect(err).ToNot(gomega.HaveOccurred())
gomega.Expect(cloudConfig).ToNot(gomega.BeNil())
gomega.Expect(cloudConfig.ActiveDirectoryAuthorityHost).To(gomega.Equal("https://login.microsoftonline.com/"))
Expand All @@ -182,18 +190,20 @@ var _ = ginkgo.Describe("Cloud", func() {
ginkgo.When("the environment is set,file is not found", func() {
ginkgo.It("should return error", func() {
os.Setenv(azclient.EnvironmentFilepathName, "notfound")
cloudConfig, err := azclient.AzureCloudConfigOverrideFromEnv(nil)
armconfig := &azclient.ARMClientConfig{}
cloudConfig := &cloud.AzurePublic
err := azclient.OverrideAzureCloudConfigFromEnv(armconfig, cloudConfig)
gomega.Expect(err).To(gomega.HaveOccurred())
gomega.Expect(cloudConfig).To(gomega.BeNil())
os.Unsetenv(azclient.EnvironmentFilepathName)
})
})
ginkgo.When("the environment is set,file is empty", func() {
ginkgo.It("should return error", func() {
os.Setenv(azclient.EnvironmentFilepathName, "notfound")
cloudConfig, err := azclient.AzureCloudConfigOverrideFromEnv(nil)
armconfig := &azclient.ARMClientConfig{}
cloudConfig := &cloud.AzurePublic
err := azclient.OverrideAzureCloudConfigFromEnv(armconfig, cloudConfig)
gomega.Expect(err).To(gomega.HaveOccurred())
gomega.Expect(cloudConfig).To(gomega.BeNil())
os.Unsetenv(azclient.EnvironmentFilepathName)
})
})
Expand All @@ -211,7 +221,11 @@ var _ = ginkgo.Describe("Cloud", func() {
}`), 0600)
gomega.Expect(err).ToNot(gomega.HaveOccurred())
os.Setenv(azclient.EnvironmentFilepathName, configFile.Name())
cloudConfig, err := azclient.AzureCloudConfigOverrideFromEnv(&cloud.AzureGovernment)
armconfig := &azclient.ARMClientConfig{
Cloud: "AzureGovernment",
}
cloudConfig := &cloud.AzureGovernment
err = azclient.OverrideAzureCloudConfigFromEnv(armconfig, cloudConfig)
gomega.Expect(err).ToNot(gomega.HaveOccurred())
gomega.Expect(cloudConfig).ToNot(gomega.BeNil())
gomega.Expect(cloudConfig.ActiveDirectoryAuthorityHost).To(gomega.Equal("https://login.chinacloudapi.cn"))
Expand Down
Loading

0 comments on commit fc0fcea

Please sign in to comment.