diff --git a/flag.go b/flag.go index 8fe2b5d..222fb21 100644 --- a/flag.go +++ b/flag.go @@ -66,14 +66,19 @@ type FlagSet struct { // // rg: // flagPattern + // flagIncludeRoleAssignment // // query: // flagPattern // flagRecursive - flagPattern string - flagRecursive bool - flagResName string - flagResType string + // flagIncludeRoleAssignment + // flagIncludeResourceGroup + flagPattern string + flagRecursive bool + flagResName string + flagResType string + flagIncludeRoleAssignment bool + flagIncludeResourceGroup bool } const ( @@ -179,6 +184,9 @@ func (flag FlagSet) DescribeCLI(mode string) string { if flag.flagPattern != "" { args = append(args, "--name-pattern="+flag.flagPattern) } + if flag.flagIncludeRoleAssignment { + args = append(args, "--include-role-assignment=true") + } case ModeQuery: if flag.flagPattern != "" { args = append(args, "--name-pattern="+flag.flagPattern) @@ -186,6 +194,12 @@ func (flag FlagSet) DescribeCLI(mode string) string { if flag.flagRecursive { args = append(args, "--recursive=true") } + if flag.flagIncludeRoleAssignment { + args = append(args, "--include-role-assignment=true") + } + if flag.flagIncludeResourceGroup { + args = append(args, "--include-resource-group=true") + } } return "aztfexport " + strings.Join(args, " ") } diff --git a/go.mod b/go.mod index 0951f86..ce7a377 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault v1.0.0 - github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.0.0 + github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.1.1 github.com/charmbracelet/bubbles v0.14.0 github.com/charmbracelet/bubbletea v0.22.1 github.com/charmbracelet/lipgloss v0.5.0 @@ -20,7 +20,7 @@ require ( github.com/hashicorp/terraform-json v0.16.0 github.com/hexops/gotextdiff v1.0.3 github.com/magodo/armid v0.0.0-20230511151020-27880e5961c3 - github.com/magodo/azlist v0.0.0-20230518102903-58631213ca2c + github.com/magodo/azlist v0.0.0-20231101012443-e30f2da262c1 github.com/magodo/aztft v0.3.1-0.20231024014716-76ffc159f6c8 github.com/magodo/spinner v0.0.0-20220720073946-50f31b2dc5a6 github.com/magodo/terraform-client-go v0.0.0-20230323074119-02ceb732dd25 diff --git a/go.sum b/go.sum index ed92b6c..ffb61b2 100644 --- a/go.sum +++ b/go.sum @@ -44,7 +44,7 @@ github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/frontdoor/armfrontdoor v1. github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/frontdoor/armfrontdoor v1.0.0/go.mod h1:fwbqrfE4XA8MI4l9ECK9LESaTaSQC/wYMoYBKHYcl/k= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/hdinsight/armhdinsight v1.0.0 h1:YiFulhmwcgOnjlNDqu1c8dVHkhNd/wlZIVcV32Pq0kA= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/hdinsight/armhdinsight v1.0.0/go.mod h1:g0o51pdbR/Zn9w3X61C+UrYfS98UpCcp8+1KTceXD0A= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal v1.0.0 h1:lMW1lD/17LUA5z1XTURo7LcVG2ICBPlyMHjIUrcFZNQ= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal v1.1.2 h1:mLY+pNLjCUeKhgnAJWAKhEUQM+RJQo2H1fuGSw1Ky1E= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/iothub/armiothub v1.1.1 h1:Dh8SxVXcSyQN76LI4IseKyrnqyTUsx336Axg8zDYSMs= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/iothub/armiothub v1.1.1/go.mod h1:fqmmortNEICbosf7BfNVO3wWs6Cz/pkxYfExJC97Vy8= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault v1.0.0 h1:Jc2KcpCDMu7wJfkrzn7fs/53QMDXH78GuqnH4HOd7zs= @@ -55,6 +55,7 @@ github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/logic/armlogic v1.1.1 h1:Y github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/logic/armlogic v1.1.1/go.mod h1:DwT51rZDyLryjioY2lt18MlJ8risPJlt8HaKdciJlMI= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/machinelearning/armmachinelearning/v3 v3.0.0 h1:C8jlM/kxDVoUbmPJPp0C6Tz8VfiuAe+Lwcdw2DeyRPE= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/machinelearning/armmachinelearning/v3 v3.0.0/go.mod h1:6IMUN/Qwv/Y6aL21XxWGcQXfRYrivO4qFPWsbf0wVJI= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/managementgroups/armmanagementgroups v1.0.0 h1:pPvTJ1dY0sA35JOeFq6TsY2xj6Z85Yo23Pj4wCCvu4o= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/monitor/armmonitor v0.7.0 h1:U6aSmNaC/WWDlHnL0e+SxQlvYmcjdoBLFjNir8AZBe0= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/monitor/armmonitor v0.7.0/go.mod h1:qDMzzI3qK0Oi9wpbRIaBoYyRYg+1UJZ0I2/Y4VxoVU4= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/msi/armmsi v0.6.0 h1:zSHpZY39hfFpVNixDoFOUeLwBBX0SIRe32HaWg03R8k= @@ -72,8 +73,8 @@ github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourceg github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.6.0/go.mod h1:KKrvyReEXgIA2D4ez2Jq5dRynJW4bOjRDkONdze2qjs= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armdeploymentscripts v1.0.0 h1:qd/BfXBy0s/cPn/hVVX+Ps0HolpC1NsHE2p+L2zB4C4= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armdeploymentscripts v1.0.0/go.mod h1:P1SgXux7JvaLh0fwpYwtY2csL+RYAc033mNha1Txlm8= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.0.0 h1:ECsQtyERDVz3NP3kvDOTLvbQhqWp/x9EsGKtb4ogUr8= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.0.0/go.mod h1:s1tW/At+xHqjNFvWU4G0c0Qv33KOhvbGNj0RCTQDV8s= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.1.1 h1:7CBQ+Ei8SP2c6ydQTGCCrS35bDxgTMfoP2miAwK++OU= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.1.1/go.mod h1:c/wcGeGx5FUPbM/JltUYHZcKmigwyVLJlDq+4HdtXaw= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/securityinsights/armsecurityinsights/v2 v2.0.0-beta.1 h1:9mTTrRpS9YeiH3n0FwWBCOd9Sg6AdQYwcpRCjK3+WQ4= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/securityinsights/armsecurityinsights/v2 v2.0.0-beta.1/go.mod h1:+Vn4YGqMk8/urNMX3IMR2lggm5cKqRQN13pUkqcfgyA= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.0.0 h1:TMEyRFKh1zaSPmoQh3kxK+xRAYVq8guCI/7SMO0F3KY= @@ -226,8 +227,8 @@ github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69 github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/magodo/armid v0.0.0-20230511151020-27880e5961c3 h1:ob6vk6PlChZvutcxcLnmPH/VNmJEuwz+TmCYCVtJqeA= github.com/magodo/armid v0.0.0-20230511151020-27880e5961c3/go.mod h1:rR8E7zfGMbmfnSQvrkFiWYdhrfTqsVSltelnZB09BwA= -github.com/magodo/azlist v0.0.0-20230518102903-58631213ca2c h1:EcZcI48XRVOFF32JYn/si26mlSeNSVJJ51+GlUQhvNg= -github.com/magodo/azlist v0.0.0-20230518102903-58631213ca2c/go.mod h1:pkK04XFrJfiki47pbsmEBUAW/fbF2OiFhK37gq4TzOk= +github.com/magodo/azlist v0.0.0-20231101012443-e30f2da262c1 h1:9SXoK38cfRZac8LwA3BmEhVjuU/JGPb6I3MKvpHA4To= +github.com/magodo/azlist v0.0.0-20231101012443-e30f2da262c1/go.mod h1:xefFDOxzRssOEjGoxvrO8jeTWlzHXbY6sCJYOt+Jh5k= github.com/magodo/aztft v0.3.1-0.20231024014716-76ffc159f6c8 h1:DaOc1N45UQ4ifLF5aTvxM/MPTcwgIyWnHUAZnEBvol4= github.com/magodo/aztft v0.3.1-0.20231024014716-76ffc159f6c8/go.mod h1:hBvWN4EMP6ofzGA5d3jffaUQMz1jATxz45aaQ0+dzLE= github.com/magodo/spinner v0.0.0-20220720073946-50f31b2dc5a6 h1:CElHO4hPXC+Eivy8sUC/WrnH3jmQzdF2x0lEXBEYul8= diff --git a/internal/meta/extension_resource.go b/internal/meta/extension_resource.go new file mode 100644 index 0000000..99585b3 --- /dev/null +++ b/internal/meta/extension_resource.go @@ -0,0 +1,41 @@ +package meta + +import ( + "strings" + + "github.com/magodo/azlist/azlist" +) + +type extBuilder struct { + includeRoleAssignment bool +} + +func (b extBuilder) Build() []azlist.ExtensionResource { + var el []azlist.ExtensionResource + if b.includeRoleAssignment { + el = append(el, azlist.ExtensionResource{ + Type: "Microsoft.Authorization/roleAssignments", + Filter: func(res, extensionRes map[string]interface{}) bool { + idRaw, ok := res["id"] + if !ok { + return false + } + id := idRaw.(string) + + propsRaw, ok := extensionRes["properties"] + if !ok { + return false + } + scopeRaw, ok := propsRaw.(map[string]interface{})["scope"] + if !ok { + return false + } + scope := scopeRaw.(string) + + return strings.EqualFold(id, scope) + }, + }) + } + + return el +} diff --git a/internal/meta/meta_query.go b/internal/meta/meta_query.go index 22f116d..4ce5f33 100644 --- a/internal/meta/meta_query.go +++ b/internal/meta/meta_query.go @@ -13,10 +13,12 @@ import ( type MetaQuery struct { baseMeta - argPredicate string - recursiveQuery bool - resourceNamePrefix string - resourceNameSuffix string + argPredicate string + recursiveQuery bool + resourceNamePrefix string + resourceNameSuffix string + includeRoleAssignment bool + includeResourceGroup bool } func NewMetaQuery(cfg config.Config) (*MetaQuery, error) { @@ -27,9 +29,11 @@ func NewMetaQuery(cfg config.Config) (*MetaQuery, error) { } meta := &MetaQuery{ - baseMeta: *baseMeta, - argPredicate: cfg.ARGPredicate, - recursiveQuery: cfg.RecursiveQuery, + baseMeta: *baseMeta, + argPredicate: cfg.ARGPredicate, + recursiveQuery: cfg.RecursiveQuery, + includeRoleAssignment: cfg.IncludeRoleAssignment, + includeResourceGroup: cfg.IncludeResourceGroup, } meta.resourceNamePrefix, meta.resourceNameSuffix = resourceNamePattern(cfg.ResourceNamePattern) @@ -97,11 +101,13 @@ func (meta *MetaQuery) ListResource(ctx context.Context) (ImportList, error) { func (meta MetaQuery) queryResourceSet(ctx context.Context, predicate string, recursive bool) (*resourceset.AzureResourceSet, error) { result, err := azlist.List(ctx, predicate, azlist.Option{ - SubscriptionId: meta.subscriptionId, - Cred: meta.azureSDKCred, - ClientOpt: meta.azureSDKClientOpt, - Parallelism: meta.parallelism, - Recursive: recursive, + SubscriptionId: meta.subscriptionId, + Cred: meta.azureSDKCred, + ClientOpt: meta.azureSDKClientOpt, + Parallelism: meta.parallelism, + Recursive: recursive, + ExtensionResourceTypes: extBuilder{includeRoleAssignment: meta.includeRoleAssignment}.Build(), + IncludeResourceGroup: meta.includeResourceGroup, }) if err != nil { return nil, fmt.Errorf("listing resource set: %v", err) diff --git a/internal/meta/meta_rg.go b/internal/meta/meta_rg.go index 34ec15e..7d90e23 100644 --- a/internal/meta/meta_rg.go +++ b/internal/meta/meta_rg.go @@ -8,15 +8,15 @@ import ( "github.com/Azure/aztfexport/internal/tfaddr" "github.com/Azure/aztfexport/pkg/config" "github.com/Azure/aztfexport/pkg/log" - "github.com/magodo/armid" "github.com/magodo/azlist/azlist" ) type MetaResourceGroup struct { baseMeta - resourceGroup string - resourceNamePrefix string - resourceNameSuffix string + resourceGroup string + resourceNamePrefix string + resourceNameSuffix string + includeRoleAssignment bool } func NewMetaResourceGroup(cfg config.Config) (*MetaResourceGroup, error) { @@ -27,8 +27,9 @@ func NewMetaResourceGroup(cfg config.Config) (*MetaResourceGroup, error) { } meta := &MetaResourceGroup{ - baseMeta: *baseMeta, - resourceGroup: cfg.ResourceGroupName, + baseMeta: *baseMeta, + resourceGroup: cfg.ResourceGroupName, + includeRoleAssignment: cfg.IncludeRoleAssignment, } meta.resourceNamePrefix, meta.resourceNameSuffix = resourceNamePattern(cfg.ResourceNamePattern) @@ -91,11 +92,13 @@ func (meta *MetaResourceGroup) ListResource(ctx context.Context) (ImportList, er func (meta MetaResourceGroup) queryResourceSet(ctx context.Context, rg string) (*resourceset.AzureResourceSet, error) { result, err := azlist.List(ctx, fmt.Sprintf("resourceGroup =~ %q", rg), azlist.Option{ - SubscriptionId: meta.subscriptionId, - Cred: meta.azureSDKCred, - ClientOpt: meta.azureSDKClientOpt, - Parallelism: meta.parallelism, - Recursive: true, + SubscriptionId: meta.subscriptionId, + Cred: meta.azureSDKCred, + ClientOpt: meta.azureSDKClientOpt, + Parallelism: meta.parallelism, + Recursive: true, + IncludeResourceGroup: true, + ExtensionResourceTypes: extBuilder{includeRoleAssignment: meta.includeRoleAssignment}.Build(), }) if err != nil { return nil, fmt.Errorf("listing resource set: %v", err) @@ -110,11 +113,5 @@ func (meta MetaResourceGroup) queryResourceSet(ctx context.Context, rg string) ( rl = append(rl, res) } - // Especially, adding the resoruce group itself to the resource set - rl = append(rl, resourceset.AzureResource{Id: &armid.ResourceGroup{ - SubscriptionId: meta.subscriptionId, - Name: meta.resourceGroup, - }}) - return &resourceset.AzureResourceSet{Resources: rl}, nil } diff --git a/main.go b/main.go index d1fbc70..cecf5c7 100644 --- a/main.go +++ b/main.go @@ -342,6 +342,12 @@ func main() { Value: "res-", Destination: &flagset.flagPattern, }, + &cli.BoolFlag{ + Name: "include-role-assignment", + EnvVars: []string{"AZTFEXPORT_INCLUDE_ROLE_ASSIGNMENT"}, + Usage: `Whether to include role assignemnts assigned to the resources exported`, + Destination: &flagset.flagIncludeRoleAssignment, + }, }, commonFlags...) queryFlags := append([]cli.Flag{ @@ -352,6 +358,12 @@ func main() { Usage: "Recursively lists child resources of the resulting query resources", Destination: &flagset.flagRecursive, }, + &cli.BoolFlag{ + Name: "include-resource-group", + EnvVars: []string{"AZTFEXPORT_INCLUDE_RESOURCE_GROUP"}, + Usage: "Include the resource groups that the exported resources belong to", + Destination: &flagset.flagIncludeResourceGroup, + }, }, resourceGroupFlags...) mappingFileFlags := append([]cli.Flag{}, commonFlags...) @@ -481,10 +493,11 @@ func main() { // Initialize the config cfg := config.Config{ - CommonConfig: commonConfig, - ResourceGroupName: rg, - ResourceNamePattern: flagset.flagPattern, - RecursiveQuery: true, + CommonConfig: commonConfig, + ResourceGroupName: rg, + ResourceNamePattern: flagset.flagPattern, + RecursiveQuery: true, + IncludeRoleAssignment: flagset.flagIncludeRoleAssignment, } return realMain(c.Context, cfg, flagset.flagNonInteractive, flagset.hflagMockClient, flagset.flagPlainUI, flagset.flagGenerateMappingFile, flagset.hflagProfile, flagset.DescribeCLI(ModeResourceGroup)) @@ -513,10 +526,12 @@ func main() { // Initialize the config cfg := config.Config{ - CommonConfig: commonConfig, - ARGPredicate: predicate, - ResourceNamePattern: flagset.flagPattern, - RecursiveQuery: flagset.flagRecursive, + CommonConfig: commonConfig, + ARGPredicate: predicate, + ResourceNamePattern: flagset.flagPattern, + RecursiveQuery: flagset.flagRecursive, + IncludeRoleAssignment: flagset.flagIncludeRoleAssignment, + IncludeResourceGroup: flagset.flagIncludeResourceGroup, } return realMain(c.Context, cfg, flagset.flagNonInteractive, flagset.hflagMockClient, flagset.flagPlainUI, flagset.flagGenerateMappingFile, flagset.hflagProfile, flagset.DescribeCLI(ModeQuery)) diff --git a/pkg/config/config.go b/pkg/config/config.go index 53ea70b..9d245bb 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -89,4 +89,10 @@ type Config struct { TFResourceName string // TFResourceName specifies the TF resource type (if empty, will try to deduce the type), this only applies to resource mode. TFResourceType string + + // IncludeRoleAssignment specifies whether to include the role assginments assigned to the exported resources, this only applies to rg and query mode + IncludeRoleAssignment bool + + // IncludeResourceGroup specifies whether to include the resource groups that the exported resources belong to, this only applies to query mode + IncludeResourceGroup bool }