Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support multiple clouds in asoctl #4033

Merged
merged 1 commit into from
May 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 30 additions & 3 deletions docs/hugo/content/tools/asoctl.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,22 +208,49 @@ When you have an existing Azure resource that needs to be managed by ASO, you ca

``` bash
$ asoctl import azure-resource --help
Import ARM resources as Custom Resources
Imports ARM resources as Custom Resources.

This command requires you to authenticate with Azure using an identity which has access to the resource(s) you would
like to import. The following authentication modes are supported:

Az-login token: az login and then use asoctl.
Managed Identity: Set the AZURE_CLIENT_ID environment variable and run on a machine with access to the managed identity.
Service Principal: Set the AZURE_SUBSCRIPTION_ID, AZURE_TENANT_ID, AZURE_CLIENT_ID, and AZURE_CLIENT_SECRET environment variables,

The following environment variables can be used to configure which cloud to use with asoctl:

AZURE_RESOURCE_MANAGER_ENDPOINT: The Azure Resource Manager endpoint.
If not specified, the default is the Public cloud resource manager endpoint.
See https://docs.microsoft.com/cli/azure/manage-clouds-azure-cli#list-available-clouds for details
about how to find available resource manager endpoints for your cloud. Note that the resource manager
endpoint is referred to as "resourceManager" in the Azure CLI.

AZURE_RESOURCE_MANAGER_AUDIENCE: The Azure Resource Manager AAD audience.
If not specified, the default is the Public cloud resource manager audience https://management.core.windows.net/.
See https://docs.microsoft.com/cli/azure/manage-clouds-azure-cli#list-available-clouds for details
about how to find available resource manager audiences for your cloud. Note that the resource manager
audience is referred to as "activeDirectoryResourceId" in the Azure CLI.

AZURE_AUTHORITY_HOST: The URL of the AAD authority.
If not specified, the default
is the AAD URL for the public cloud: https://login.microsoftonline.com/. See
https://docs.microsoft.com/azure/active-directory/develop/authentication-national-cloud

Usage:
asoctl import azure-resource <ARM/ID/of/resource> [flags]

Flags:
-a, --annotations strings Add the specified annotations to the imported resources. Multiple comma-separated annotations can be specified (example.com/myannotation=foo,example.com/myannotation2=bar) or the --annotations (-a) argument can be used multiple times (-a example.com/myannotation=foo -a example.com/myannotation2=bar)
-a, --annotation strings Add the specified annotations to the imported resources. Multiple comma-separated annotations can be specified (--annotation example.com/myannotation=foo,example.com/myannotation2=bar) or the --annotation (-a) argument can be used multiple times (-a example.com/myannotation=foo -a example.com/myannotation2=bar)
-h, --help help for azure-resource
-l, --labels strings Add the specified labels to the imported resources. Multiple comma-separated labels can be specified (example.com/mylabel=foo,example.com/mylabel2=bar) or the --labels (-l) argument can be used multiple times (-l example.com/mylabel=foo -l example.com/mylabel2=bar)
-l, --label strings Add the specified labels to the imported resources. Multiple comma-separated labels can be specified (--label example.com/mylabel=foo,example.com/mylabel2=bar) or the --label (-l) argument can be used multiple times (-l example.com/mylabel=foo -l example.com/mylabel2=bar)
-n, --namespace string Write the imported resources to the specified namespace
-o, --output string Write ARM resource CRDs to a single file
-f, --output-folder string Write ARM resource CRDs to individual files in a folder

Global Flags:
--quiet Silence most logging
--verbose Enable verbose logging

```

The `asoctl import azure-resource` command will accept any number of ARM resource Ids.
Expand Down
85 changes: 78 additions & 7 deletions v2/cmd/asoctl/cmd/import_azure_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,20 @@ package cmd

import (
"context"
"os"
"sync"

"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/pkg/errors"
"github.com/spf13/cobra"

"github.com/Azure/azure-service-operator/v2/api"
"github.com/Azure/azure-service-operator/v2/cmd/asoctl/internal/importing"
internalconfig "github.com/Azure/azure-service-operator/v2/internal/config"
"github.com/Azure/azure-service-operator/v2/internal/genericarmclient"
"github.com/Azure/azure-service-operator/v2/internal/version"

"github.com/Azure/azure-service-operator/v2/cmd/asoctl/internal/importing"
"github.com/Azure/azure-service-operator/v2/pkg/common/config"
)

func newImportAzureResourceCommand() *cobra.Command {
Expand All @@ -26,10 +29,38 @@ func newImportAzureResourceCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "azure-resource <ARM/ID/of/resource>",
Short: "Import ARM resources as Custom Resources",
Args: cobra.MinimumNArgs(1),
Long: `Imports ARM resources as Custom Resources.

This command requires you to authenticate with Azure using an identity which has access to the resource(s) you would
like to import. The following authentication modes are supported:

Az-login token: az login and then use asoctl.
Managed Identity: Set the AZURE_CLIENT_ID environment variable and run on a machine with access to the managed identity.
Service Principal: Set the AZURE_SUBSCRIPTION_ID, AZURE_TENANT_ID, AZURE_CLIENT_ID, and AZURE_CLIENT_SECRET environment variables,

The following environment variables can be used to configure which cloud to use with asoctl:

AZURE_RESOURCE_MANAGER_ENDPOINT: The Azure Resource Manager endpoint.
If not specified, the default is the Public cloud resource manager endpoint.
See https://docs.microsoft.com/cli/azure/manage-clouds-azure-cli#list-available-clouds for details
about how to find available resource manager endpoints for your cloud. Note that the resource manager
endpoint is referred to as "resourceManager" in the Azure CLI.

AZURE_RESOURCE_MANAGER_AUDIENCE: The Azure Resource Manager AAD audience.
If not specified, the default is the Public cloud resource manager audience https://management.core.windows.net/.
See https://docs.microsoft.com/cli/azure/manage-clouds-azure-cli#list-available-clouds for details
about how to find available resource manager audiences for your cloud. Note that the resource manager
audience is referred to as "activeDirectoryResourceId" in the Azure CLI.

AZURE_AUTHORITY_HOST: The URL of the AAD authority.
If not specified, the default
is the AAD URL for the public cloud: https://login.microsoftonline.com/. See
https://docs.microsoft.com/azure/active-directory/develop/authentication-national-cloud
`,
Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
return importAzureResource(ctx, args, options)
return importAzureResource(ctx, args, &options)
},
}

Expand Down Expand Up @@ -70,11 +101,9 @@ func newImportAzureResourceCommand() *cobra.Command {
}

// importAzureResource imports an ARM resource and writes the YAML to stdout or a file
func importAzureResource(ctx context.Context, armIDs []string, options importAzureResourceOptions) error {
func importAzureResource(ctx context.Context, armIDs []string, options *importAzureResourceOptions) error {
log, progress := CreateLoggerAndProgressBar()

// TODO: Support other Azure clouds
activeCloud := cloud.AzurePublic
creds, err := azidentity.NewDefaultAzureCredential(nil)
if err != nil {
return errors.Wrap(err, "unable to get default Azure credential")
Expand All @@ -84,6 +113,7 @@ func importAzureResource(ctx context.Context, armIDs []string, options importAzu
UserAgent: "asoctl/" + version.BuildVersion,
}

activeCloud := options.cloud()
client, err := genericarmclient.NewGenericClient(activeCloud, creds, clientOptions)
if err != nil {
return errors.Wrapf(err, "failed to create ARM client")
Expand Down Expand Up @@ -171,6 +201,11 @@ type importAzureResourceOptions struct {
namespace string
annotations []string
labels []string

readCloud sync.Once
azureAuthorityHost string
resourceManagerEndpoint string
resourceManagerAudience string
}

func (option *importAzureResourceOptions) writeToFile() (string, bool) {
Expand All @@ -188,3 +223,39 @@ func (option *importAzureResourceOptions) writeToFolder() (string, bool) {

return "", false
}

func (option *importAzureResourceOptions) cloud() cloud.Configuration {
option.readCloud.Do(func() {
option.azureAuthorityHost = os.Getenv(config.AzureAuthorityHost)
option.resourceManagerEndpoint = os.Getenv(config.ResourceManagerEndpoint)
option.resourceManagerAudience = os.Getenv(config.ResourceManagerAudience)

if option.azureAuthorityHost == "" {
option.azureAuthorityHost = internalconfig.DefaultAADAuthorityHost
}
if option.resourceManagerEndpoint == "" {
option.resourceManagerEndpoint = internalconfig.DefaultEndpoint
}
if option.resourceManagerAudience == "" {
option.resourceManagerAudience = internalconfig.DefaultAudience
}
})

hasDefaultAzureAuthorityHost := option.azureAuthorityHost == internalconfig.DefaultAADAuthorityHost
hasDefaultResourceManagerEndpoint := option.resourceManagerEndpoint == internalconfig.DefaultEndpoint
hasDefaultResourceManagerAudience := option.resourceManagerAudience == internalconfig.DefaultAudience

if hasDefaultAzureAuthorityHost && hasDefaultResourceManagerEndpoint && hasDefaultResourceManagerAudience {
return cloud.AzurePublic
}

return cloud.Configuration{
ActiveDirectoryAuthorityHost: option.azureAuthorityHost,
Services: map[cloud.ServiceName]cloud.ServiceConfiguration{
cloud.ResourceManager: {
Endpoint: option.resourceManagerEndpoint,
Audience: option.resourceManagerAudience,
},
},
}
}
Loading