From 936cdc74346e91d738ed0c06cc740bb2314c0f47 Mon Sep 17 00:00:00 2001 From: magodo Date: Sat, 28 Jan 2023 17:02:27 +0800 Subject: [PATCH 1/3] TODO: not work, need helper to support chains --- azlist/azlist.go | 72 ++++++++++++++++++++++++++++++++++++++++---- azlist/client.go | 63 ++++----------------------------------- go.mod | 13 ++++---- go.sum | 23 +++++++-------- main.go | 77 +++++++++++++++++++++++++++++++++++++++--------- 5 files changed, 152 insertions(+), 96 deletions(-) diff --git a/azlist/azlist.go b/azlist/azlist.go index 30412b3..1eaec11 100644 --- a/azlist/azlist.go +++ b/azlist/azlist.go @@ -11,8 +11,12 @@ import ( "strings" "github.com/Azure/azure-sdk-for-go/sdk/azcore" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph" "github.com/magodo/armid" + "github.com/magodo/azure-sdk-for-go-helper/authentication" "github.com/magodo/workerpool" ) @@ -36,6 +40,21 @@ type ARMSchemaEntry struct { } type Option struct { + // Required + SubscriptionId string + + // Optional + + // Auth related + TenantID string + ClientID string + ClientSecret string + ClientCertPath string + ClientCertPassword string + // Env can be one of "public", "china", "usgovernment". Defaults to "public". + Env string + + // Feature related Parallelism int Recursive bool IncludeManaged bool @@ -62,20 +81,61 @@ type ListResult struct { Errors []ListError } -func List(ctx context.Context, subscriptionId, predicate string, opt *Option) (*ListResult, error) { - if opt == nil { - opt = defaultOption() +func List(ctx context.Context, predicate string, opt Option) (*ListResult, error) { + if opt.SubscriptionId == "" { + return nil, fmt.Errorf("subscription id is empty") + } + if opt.Parallelism == 0 { + opt.Parallelism = runtime.NumCPU() + } + if opt.Env == "" { + opt.Env = "public" } - log.Printf("[INFO] List for subscription %s via predicate %s, with option %#v", subscriptionId, predicate, opt) + log.Printf("[INFO] List for subscription %s via predicate %s (parallelism: %d | recursive %t | include managed %t)", opt.SubscriptionId, predicate, opt.Parallelism, opt.Recursive, opt.IncludeManaged) + + var cloudCfg cloud.Configuration + switch strings.ToLower(opt.Env) { + case "public": + cloudCfg = cloud.AzurePublic + case "usgovernment": + cloudCfg = cloud.AzureGovernment + case "china": + cloudCfg = cloud.AzureChina + default: + return nil, fmt.Errorf("unknown environment specified: %q", opt.Env) + } + + clientOpt := arm.ClientOptions{ + ClientOptions: policy.ClientOptions{ + Cloud: cloudCfg, + Telemetry: policy.TelemetryOptions{ + ApplicationID: "azlist", + Disabled: false, + }, + Logging: policy.LogOptions{ + IncludeBody: true, + }, + }, + } + + authOpt := authentication.Option{ + ClientOptions: clientOpt.ClientOptions, + TenantID: opt.TenantID, + ClientID: opt.ClientID, + ClientSecret: opt.ClientSecret, + ClientCertPath: opt.ClientCertPath, + ClientCertPassword: opt.ClientCertPassword, + } - client, err := NewClient(subscriptionId) + log.Printf("[INFO] New Client") + client, err := NewClient(opt.SubscriptionId, authOpt, clientOpt) if err != nil { return nil, fmt.Errorf("new client: %v", err) } log.Printf("[INFO] Listing tracked resources") - rl, err := ListTrackedResources(ctx, client, subscriptionId, predicate) + rl, err := ListTrackedResources(ctx, client, opt.SubscriptionId, predicate) if err != nil { return nil, err } diff --git a/azlist/client.go b/azlist/client.go index 1438433..0f4e5bd 100644 --- a/azlist/client.go +++ b/azlist/client.go @@ -2,15 +2,11 @@ package azlist import ( "fmt" - "os" - "strings" "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" - "github.com/Azure/azure-sdk-for-go/sdk/azidentity" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph" "github.com/magodo/azlist/armresources" + "github.com/magodo/azure-sdk-for-go-helper/authentication" ) type Client struct { @@ -18,67 +14,18 @@ type Client struct { resourceGraph *armresourcegraph.Client } -func NewClient(subscriptionId string) (*Client, error) { - env := "public" - if v := os.Getenv("ARM_ENVIRONMENT"); v != "" { - env = v - } - - var cloudCfg cloud.Configuration - switch strings.ToLower(env) { - case "public": - cloudCfg = cloud.AzurePublic - case "usgovernment": - cloudCfg = cloud.AzureGovernment - case "china": - cloudCfg = cloud.AzureChina - default: - return nil, fmt.Errorf("unknown environment specified: %q", env) - } - - // Maps the auth related environment variables used in the provider to what azidentity honors. - if v, ok := os.LookupEnv("ARM_TENANT_ID"); ok { - os.Setenv("AZURE_TENANT_ID", v) - } - if v, ok := os.LookupEnv("ARM_CLIENT_ID"); ok { - os.Setenv("AZURE_CLIENT_ID", v) - } - if v, ok := os.LookupEnv("ARM_CLIENT_SECRET"); ok { - os.Setenv("AZURE_CLIENT_SECRET", v) - } - if v, ok := os.LookupEnv("ARM_CLIENT_CERTIFICATE_PATH"); ok { - os.Setenv("AZURE_CLIENT_CERTIFICATE_PATH", v) - } - - cred, err := azidentity.NewDefaultAzureCredential(&azidentity.DefaultAzureCredentialOptions{ - ClientOptions: policy.ClientOptions{ - Cloud: cloudCfg, - }, - TenantID: os.Getenv("ARM_TENANT_ID"), - }) +func NewClient(subscriptionId string, authOpt authentication.Option, clientOpt arm.ClientOptions) (*Client, error) { + cred, err := authentication.NewAzureCredential(&authOpt) if err != nil { return nil, fmt.Errorf("failed to obtain a credential: %v", err) } - opt := &arm.ClientOptions{ - ClientOptions: policy.ClientOptions{ - Cloud: cloudCfg, - Telemetry: policy.TelemetryOptions{ - ApplicationID: "azlist", - Disabled: false, - }, - Logging: policy.LogOptions{ - IncludeBody: true, - }, - }, - } - - resClient, err := armresources.NewClient(subscriptionId, cred, opt) + resClient, err := armresources.NewClient(subscriptionId, cred, &clientOpt) if err != nil { return nil, err } - argClient, err := armresourcegraph.NewClient(cred, opt) + argClient, err := armresourcegraph.NewClient(cred, &clientOpt) if err != nil { return nil, err } diff --git a/go.mod b/go.mod index 8504a1b..506edcf 100644 --- a/go.mod +++ b/go.mod @@ -3,23 +3,24 @@ module github.com/magodo/azlist go 1.19 require ( - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.3 - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.3.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.6.0 github.com/hashicorp/go-hclog v1.3.1 github.com/magodo/armid v0.0.0-20220915030809-9ed860f93894 + github.com/magodo/azure-sdk-for-go-helper v0.0.0-00010101000000-000000000000 github.com/magodo/workerpool v0.0.0-20211124060943-1c48f3e5a514 github.com/stretchr/testify v1.7.5 github.com/urfave/cli/v2 v2.16.3 ) require ( - github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect - github.com/AzureAD/microsoft-authentication-library-for-go v0.5.1 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.1 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v0.8.1 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/fatih/color v1.13.0 // indirect - github.com/golang-jwt/jwt v3.2.1+incompatible // indirect + github.com/golang-jwt/jwt/v4 v4.4.2 // indirect github.com/google/uuid v1.1.1 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect @@ -36,3 +37,5 @@ require ( golang.org/x/text v0.3.7 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) + +replace github.com/magodo/azure-sdk-for-go-helper => ../azure-sdk-for-go-helper diff --git a/go.sum b/go.sum index cf2e79f..6e487a3 100644 --- a/go.sum +++ b/go.sum @@ -1,13 +1,13 @@ -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.3 h1:8LoU8N2lIUzkmstvwXvVfniMZlFbesfT2AmA1aqvRr8= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.3/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4SathZPhDhF4mVwpBMFlYjyAqy8= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.3.0 h1:VuHAcMq8pU1IWNT/m5yRaGqbK0BiQKHT8X4DTp9CHdI= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.3.0/go.mod h1:tZoQYdDZNOiIjdSn0dVWVfl0NEPGOJqVLzSrcFk4Is0= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.1 h1:T8quHYlUGyb/oqtSTwqlCr1ilJHrDv+ZtpSfo+hm1BU= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.1/go.mod h1:gLa1CL2RNE4s7M3yopJ/p0iq5DdY6Yv5ZUt9MTRZOQM= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2 h1:+5VZ72z0Qan5Bog5C+ZkgSqUbeVUd9wgtHOrIKuc5b8= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.6.0 h1:ofIfA+/dTgrqhykfrz+GbFtPAtE697LAOCSw/8AQbwI= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.6.0/go.mod h1:KKrvyReEXgIA2D4ez2Jq5dRynJW4bOjRDkONdze2qjs= -github.com/AzureAD/microsoft-authentication-library-for-go v0.5.1 h1:BWe8a+f/t+7KY7zH2mqygeUD0t8hNFXe08p1Pb3/jKE= -github.com/AzureAD/microsoft-authentication-library-for-go v0.5.1/go.mod h1:Vt9sXTKwMyGcOxSmLDMnGPgqsUg7m8pe215qMLrDXw4= +github.com/AzureAD/microsoft-authentication-library-for-go v0.8.1 h1:oPdPEZFSbl7oSPEAIPMPBMUmiL+mqgzBJwM/9qYcwNg= +github.com/AzureAD/microsoft-authentication-library-for-go v0.8.1/go.mod h1:4qFor3D/HDsvBME35Xy9rwW9DecL+M2sNw1ybjPtwA0= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -16,9 +16,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/dnaeon/go-vcr v1.1.0 h1:ReYa/UBrRyQdant9B4fNHGoCNKw6qh6P0fsdGmZpR7c= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c= -github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= -github.com/golang-jwt/jwt/v4 v4.2.0 h1:besgBTC8w8HjP6NzQdxwKH9Z5oQMZ24ThTrHp3cZ8eU= +github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs= +github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= @@ -39,7 +38,6 @@ github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -62,7 +60,6 @@ golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR3 golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/main.go b/main.go index e41bd8e..c6fcea5 100644 --- a/main.go +++ b/main.go @@ -14,13 +14,19 @@ import ( func main() { var ( - flagSubscriptionId string - flagRecursive bool - flagWithBody bool - flagIncludeManaged bool - flagParallelism int - flagPrintError bool - flagVerbose bool + flagTenantId string + flagClientId string + flagClientSecret string + flagClientCertPath string + flagClientCertPassword string + flagEnvironment string + flagSubscriptionId string + flagRecursive bool + flagWithBody bool + flagIncludeManaged bool + flagParallelism int + flagPrintError bool + flagVerbose bool ) app := &cli.App{ @@ -30,8 +36,44 @@ func main() { UsageText: "azlist [option] ", Flags: []cli.Flag{ &cli.StringFlag{ - Name: "subscription-id", - // Honor the "ARM_SUBSCRIPTION_ID" as is used by the AzureRM provider, for easier use. + Name: "client-id", + EnvVars: []string{"AZLIST_CLIENT_ID", "ARM_CLIENT_ID"}, + Usage: "The client id", + Destination: &flagClientId, + }, + &cli.StringFlag{ + Name: "client-secret", + EnvVars: []string{"AZLIST_CLIENT_SECRET", "ARM_CLIENT_SECRET"}, + Usage: "The client secret", + Destination: &flagClientSecret, + }, + &cli.StringFlag{ + Name: "client-certificate-path", + EnvVars: []string{"AZLIST_CLIENT_CERTIFICATE_PATH", "ARM_CLIENT_CERTIFICATE_PATH"}, + Usage: "The client certificate path", + Destination: &flagClientCertPath, + }, + &cli.StringFlag{ + Name: "client-certificate-password", + EnvVars: []string{"AZLIST_CLIENT_CERTIFICATE_PASSWORD", "ARM_CLIENT_CERTIFICATE_PASSWORD"}, + Usage: "The client certificate password", + Destination: &flagClientCertPassword, + }, + &cli.StringFlag{ + Name: "tenant-id", + EnvVars: []string{"AZLIST_TENANT_ID", "ARM_TENANT_ID"}, + Usage: "The tenant id", + Destination: &flagTenantId, + }, + &cli.StringFlag{ + Name: "env", + EnvVars: []string{"AZLIST_ENV"}, + Usage: `The environment. Can be one of "public", "china", "usgovernment".`, + Destination: &flagEnvironment, + Value: "public", + }, + &cli.StringFlag{ + Name: "subscription-id", EnvVars: []string{"AZLIST_SUBSCRIPTION_ID", "ARM_SUBSCRIPTION_ID"}, Aliases: []string{"s"}, Required: true, @@ -104,13 +146,20 @@ func main() { }) } - opt := &azlist.Option{ - Parallelism: flagParallelism, - Recursive: flagRecursive, - IncludeManaged: flagIncludeManaged, + opt := azlist.Option{ + SubscriptionId: flagSubscriptionId, + TenantID: flagTenantId, + ClientID: flagClientId, + ClientSecret: flagClientSecret, + ClientCertPath: flagClientCertPath, + ClientCertPassword: flagClientCertPassword, + Env: flagEnvironment, + Parallelism: flagParallelism, + Recursive: flagRecursive, + IncludeManaged: flagIncludeManaged, } - result, err := azlist.List(ctx.Context, flagSubscriptionId, ctx.Args().First(), opt) + result, err := azlist.List(ctx.Context, ctx.Args().First(), opt) if err != nil { return err } From b4da68f57578f9a0aa0b1a733314da5253e39b3a Mon Sep 17 00:00:00 2001 From: magodo Date: Sat, 28 Jan 2023 17:16:56 +0800 Subject: [PATCH 2/3] List() option accepts a credential --- azlist/azlist.go | 28 +++---------- azlist/client.go | 11 +---- go.mod | 5 +-- main.go | 106 +++++++++++++++++++++++------------------------ 4 files changed, 62 insertions(+), 88 deletions(-) diff --git a/azlist/azlist.go b/azlist/azlist.go index 1eaec11..d858658 100644 --- a/azlist/azlist.go +++ b/azlist/azlist.go @@ -16,7 +16,6 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph" "github.com/magodo/armid" - "github.com/magodo/azure-sdk-for-go-helper/authentication" "github.com/magodo/workerpool" ) @@ -42,19 +41,10 @@ type ARMSchemaEntry struct { type Option struct { // Required SubscriptionId string + Cred azcore.TokenCredential // Optional - - // Auth related - TenantID string - ClientID string - ClientSecret string - ClientCertPath string - ClientCertPassword string - // Env can be one of "public", "china", "usgovernment". Defaults to "public". - Env string - - // Feature related + Env string Parallelism int Recursive bool IncludeManaged bool @@ -82,6 +72,9 @@ type ListResult struct { } func List(ctx context.Context, predicate string, opt Option) (*ListResult, error) { + if opt.Cred == nil { + return nil, fmt.Errorf("token credential is empty") + } if opt.SubscriptionId == "" { return nil, fmt.Errorf("subscription id is empty") } @@ -119,17 +112,8 @@ func List(ctx context.Context, predicate string, opt Option) (*ListResult, error }, } - authOpt := authentication.Option{ - ClientOptions: clientOpt.ClientOptions, - TenantID: opt.TenantID, - ClientID: opt.ClientID, - ClientSecret: opt.ClientSecret, - ClientCertPath: opt.ClientCertPath, - ClientCertPassword: opt.ClientCertPassword, - } - log.Printf("[INFO] New Client") - client, err := NewClient(opt.SubscriptionId, authOpt, clientOpt) + client, err := NewClient(opt.SubscriptionId, opt.Cred, clientOpt) if err != nil { return nil, fmt.Errorf("new client: %v", err) } diff --git a/azlist/client.go b/azlist/client.go index 0f4e5bd..f2f54c0 100644 --- a/azlist/client.go +++ b/azlist/client.go @@ -1,12 +1,10 @@ package azlist import ( - "fmt" - + "github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph" "github.com/magodo/azlist/armresources" - "github.com/magodo/azure-sdk-for-go-helper/authentication" ) type Client struct { @@ -14,12 +12,7 @@ type Client struct { resourceGraph *armresourcegraph.Client } -func NewClient(subscriptionId string, authOpt authentication.Option, clientOpt arm.ClientOptions) (*Client, error) { - cred, err := authentication.NewAzureCredential(&authOpt) - if err != nil { - return nil, fmt.Errorf("failed to obtain a credential: %v", err) - } - +func NewClient(subscriptionId string, cred azcore.TokenCredential, clientOpt arm.ClientOptions) (*Client, error) { resClient, err := armresources.NewClient(subscriptionId, cred, &clientOpt) if err != nil { return nil, err diff --git a/go.mod b/go.mod index 506edcf..e5c237a 100644 --- a/go.mod +++ b/go.mod @@ -4,17 +4,16 @@ go 1.19 require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.3.0 + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.1 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.6.0 github.com/hashicorp/go-hclog v1.3.1 github.com/magodo/armid v0.0.0-20220915030809-9ed860f93894 - github.com/magodo/azure-sdk-for-go-helper v0.0.0-00010101000000-000000000000 github.com/magodo/workerpool v0.0.0-20211124060943-1c48f3e5a514 github.com/stretchr/testify v1.7.5 github.com/urfave/cli/v2 v2.16.3 ) require ( - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v0.8.1 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect @@ -37,5 +36,3 @@ require ( golang.org/x/text v0.3.7 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) - -replace github.com/magodo/azure-sdk-for-go-helper => ../azure-sdk-for-go-helper diff --git a/main.go b/main.go index c6fcea5..09221e5 100644 --- a/main.go +++ b/main.go @@ -4,8 +4,12 @@ import ( "encoding/json" "fmt" "os" + "strings" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud" azlog "github.com/Azure/azure-sdk-for-go/sdk/azcore/log" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" + "github.com/Azure/azure-sdk-for-go/sdk/azidentity" "github.com/hashicorp/go-hclog" "github.com/magodo/azlist/azlist" @@ -14,19 +18,14 @@ import ( func main() { var ( - flagTenantId string - flagClientId string - flagClientSecret string - flagClientCertPath string - flagClientCertPassword string - flagEnvironment string - flagSubscriptionId string - flagRecursive bool - flagWithBody bool - flagIncludeManaged bool - flagParallelism int - flagPrintError bool - flagVerbose bool + flagEnvironment string + flagSubscriptionId string + flagRecursive bool + flagWithBody bool + flagIncludeManaged bool + flagParallelism int + flagPrintError bool + flagVerbose bool ) app := &cli.App{ @@ -35,36 +34,6 @@ func main() { Usage: "List Azure resources by an Azure Resource Graph `where` predicate", UsageText: "azlist [option] ", Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "client-id", - EnvVars: []string{"AZLIST_CLIENT_ID", "ARM_CLIENT_ID"}, - Usage: "The client id", - Destination: &flagClientId, - }, - &cli.StringFlag{ - Name: "client-secret", - EnvVars: []string{"AZLIST_CLIENT_SECRET", "ARM_CLIENT_SECRET"}, - Usage: "The client secret", - Destination: &flagClientSecret, - }, - &cli.StringFlag{ - Name: "client-certificate-path", - EnvVars: []string{"AZLIST_CLIENT_CERTIFICATE_PATH", "ARM_CLIENT_CERTIFICATE_PATH"}, - Usage: "The client certificate path", - Destination: &flagClientCertPath, - }, - &cli.StringFlag{ - Name: "client-certificate-password", - EnvVars: []string{"AZLIST_CLIENT_CERTIFICATE_PASSWORD", "ARM_CLIENT_CERTIFICATE_PASSWORD"}, - Usage: "The client certificate password", - Destination: &flagClientCertPassword, - }, - &cli.StringFlag{ - Name: "tenant-id", - EnvVars: []string{"AZLIST_TENANT_ID", "ARM_TENANT_ID"}, - Usage: "The tenant id", - Destination: &flagTenantId, - }, &cli.StringFlag{ Name: "env", EnvVars: []string{"AZLIST_ENV"}, @@ -146,17 +115,48 @@ func main() { }) } + cloudCfg := cloud.AzurePublic + switch strings.ToLower(flagEnvironment) { + case "public": + cloudCfg = cloud.AzurePublic + case "usgovernment": + cloudCfg = cloud.AzureGovernment + case "china": + cloudCfg = cloud.AzureChina + default: + return fmt.Errorf("unknown environment specified: %q", flagEnvironment) + } + + if v, ok := os.LookupEnv("ARM_TENANT_ID"); ok { + os.Setenv("AZURE_TENANT_ID", v) + } + if v, ok := os.LookupEnv("ARM_CLIENT_ID"); ok { + os.Setenv("AZURE_CLIENT_ID", v) + } + if v, ok := os.LookupEnv("ARM_CLIENT_SECRET"); ok { + os.Setenv("AZURE_CLIENT_SECRET", v) + } + if v, ok := os.LookupEnv("ARM_CLIENT_CERTIFICATE_PATH"); ok { + os.Setenv("AZURE_CLIENT_CERTIFICATE_PATH", v) + } + + cred, err := azidentity.NewDefaultAzureCredential(&azidentity.DefaultAzureCredentialOptions{ + ClientOptions: policy.ClientOptions{ + Cloud: cloudCfg, + }, + TenantID: os.Getenv("ARM_TENANT_ID"), + }) + if err != nil { + return fmt.Errorf("failed to obtain a credential: %v", err) + } + opt := azlist.Option{ - SubscriptionId: flagSubscriptionId, - TenantID: flagTenantId, - ClientID: flagClientId, - ClientSecret: flagClientSecret, - ClientCertPath: flagClientCertPath, - ClientCertPassword: flagClientCertPassword, - Env: flagEnvironment, - Parallelism: flagParallelism, - Recursive: flagRecursive, - IncludeManaged: flagIncludeManaged, + SubscriptionId: flagSubscriptionId, + Cred: cred, + Env: flagEnvironment, + Parallelism: flagParallelism, + Recursive: flagRecursive, + IncludeManaged: flagIncludeManaged, } result, err := azlist.List(ctx.Context, ctx.Args().First(), opt) From c2096affb741029b387791bf6a4218379e633f42 Mon Sep 17 00:00:00 2001 From: magodo Date: Sun, 29 Jan 2023 10:18:23 +0800 Subject: [PATCH 3/3] Option accepts arm.ClientOptions --- azlist/azlist.go | 34 ++-------------------------------- main.go | 19 ++++++++++++++++--- 2 files changed, 18 insertions(+), 35 deletions(-) diff --git a/azlist/azlist.go b/azlist/azlist.go index d858658..ddf83e7 100644 --- a/azlist/azlist.go +++ b/azlist/azlist.go @@ -12,8 +12,6 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph" "github.com/magodo/armid" "github.com/magodo/workerpool" @@ -42,9 +40,9 @@ type Option struct { // Required SubscriptionId string Cred azcore.TokenCredential + ClientOpt arm.ClientOptions // Optional - Env string Parallelism int Recursive bool IncludeManaged bool @@ -81,39 +79,11 @@ func List(ctx context.Context, predicate string, opt Option) (*ListResult, error if opt.Parallelism == 0 { opt.Parallelism = runtime.NumCPU() } - if opt.Env == "" { - opt.Env = "public" - } log.Printf("[INFO] List for subscription %s via predicate %s (parallelism: %d | recursive %t | include managed %t)", opt.SubscriptionId, predicate, opt.Parallelism, opt.Recursive, opt.IncludeManaged) - var cloudCfg cloud.Configuration - switch strings.ToLower(opt.Env) { - case "public": - cloudCfg = cloud.AzurePublic - case "usgovernment": - cloudCfg = cloud.AzureGovernment - case "china": - cloudCfg = cloud.AzureChina - default: - return nil, fmt.Errorf("unknown environment specified: %q", opt.Env) - } - - clientOpt := arm.ClientOptions{ - ClientOptions: policy.ClientOptions{ - Cloud: cloudCfg, - Telemetry: policy.TelemetryOptions{ - ApplicationID: "azlist", - Disabled: false, - }, - Logging: policy.LogOptions{ - IncludeBody: true, - }, - }, - } - log.Printf("[INFO] New Client") - client, err := NewClient(opt.SubscriptionId, opt.Cred, clientOpt) + client, err := NewClient(opt.SubscriptionId, opt.Cred, opt.ClientOpt) if err != nil { return nil, fmt.Errorf("new client: %v", err) } diff --git a/main.go b/main.go index 09221e5..6d01909 100644 --- a/main.go +++ b/main.go @@ -6,6 +6,7 @@ import ( "os" "strings" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm" "github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud" azlog "github.com/Azure/azure-sdk-for-go/sdk/azcore/log" "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" @@ -140,11 +141,22 @@ func main() { os.Setenv("AZURE_CLIENT_CERTIFICATE_PATH", v) } - cred, err := azidentity.NewDefaultAzureCredential(&azidentity.DefaultAzureCredentialOptions{ + clientOpt := arm.ClientOptions{ ClientOptions: policy.ClientOptions{ Cloud: cloudCfg, + Telemetry: policy.TelemetryOptions{ + ApplicationID: "azlist", + Disabled: false, + }, + Logging: policy.LogOptions{ + IncludeBody: true, + }, }, - TenantID: os.Getenv("ARM_TENANT_ID"), + } + + cred, err := azidentity.NewDefaultAzureCredential(&azidentity.DefaultAzureCredentialOptions{ + ClientOptions: clientOpt.ClientOptions, + TenantID: os.Getenv("ARM_TENANT_ID"), }) if err != nil { return fmt.Errorf("failed to obtain a credential: %v", err) @@ -153,7 +165,8 @@ func main() { opt := azlist.Option{ SubscriptionId: flagSubscriptionId, Cred: cred, - Env: flagEnvironment, + ClientOpt: clientOpt, + Parallelism: flagParallelism, Recursive: flagRecursive, IncludeManaged: flagIncludeManaged,