diff --git a/flag.go b/flag.go index e71f5e2..a614df1 100644 --- a/flag.go +++ b/flag.go @@ -42,6 +42,7 @@ type FlagSet struct { flagGenerateMappingFile bool flagHCLOnly bool flagModulePath string + flagGenerateImportBlock bool // common flags (auth) flagUseEnvironmentCred bool @@ -143,6 +144,9 @@ func (flag FlagSet) DescribeCLI(mode string) string { if flag.flagModulePath != "" { args = append(args, "--module-path="+flag.flagModulePath) } + if !flag.flagGenerateImportBlock { + args = append(args, "--generate-import-block=true") + } if flag.flagUseEnvironmentCred { args = append(args, "--use-environment-cred=true") @@ -352,6 +356,7 @@ func (f FlagSet) BuildCommonConfig() (config.CommonConfig, error) { Parallelism: f.flagParallelism, HCLOnly: f.flagHCLOnly, ModulePath: f.flagModulePath, + GenerateImportBlock: f.flagGenerateImportBlock, TelemetryClient: initTelemetryClient(f.flagSubscriptionId), } diff --git a/internal/meta/base_meta.go b/internal/meta/base_meta.go index dd5d75c..68f2c4f 100644 --- a/internal/meta/base_meta.go +++ b/internal/meta/base_meta.go @@ -10,7 +10,6 @@ import ( "path/filepath" "strings" - "github.com/hashicorp/go-version" tfjson "github.com/hashicorp/terraform-json" "github.com/Azure/aztfexport/pkg/config" @@ -78,21 +77,22 @@ type BaseMeta interface { var _ BaseMeta = &baseMeta{} type baseMeta struct { - subscriptionId string - azureSDKCred azcore.TokenCredential - azureSDKClientOpt arm.ClientOptions - outdir string - outputFileNames config.OutputFileNames - tf *tfexec.Terraform - resourceClient *armresources.Client - providerVersion string - devProvider bool - providerName string - backendType string - backendConfig []string - providerConfig map[string]cty.Value - fullConfig bool - parallelism int + subscriptionId string + azureSDKCred azcore.TokenCredential + azureSDKClientOpt arm.ClientOptions + outdir string + outputFileNames config.OutputFileNames + tf *tfexec.Terraform + resourceClient *armresources.Client + providerVersion string + devProvider bool + providerName string + backendType string + backendConfig []string + providerConfig map[string]cty.Value + fullConfig bool + parallelism int + generateImportFile bool hclOnly bool tfclient tfclient.Client @@ -202,22 +202,23 @@ func NewBaseMeta(cfg config.CommonConfig) (*baseMeta, error) { } meta := &baseMeta{ - subscriptionId: cfg.SubscriptionId, - azureSDKCred: cfg.AzureSDKCredential, - azureSDKClientOpt: cfg.AzureSDKClientOption, - outdir: cfg.OutputDir, - outputFileNames: outputFileNames, - resourceClient: resClient, - providerVersion: cfg.ProviderVersion, - devProvider: cfg.DevProvider, - backendType: cfg.BackendType, - backendConfig: cfg.BackendConfig, - providerConfig: cfg.ProviderConfig, - providerName: cfg.ProviderName, - fullConfig: cfg.FullConfig, - parallelism: cfg.Parallelism, - hclOnly: cfg.HCLOnly, - tfclient: cfg.TFClient, + subscriptionId: cfg.SubscriptionId, + azureSDKCred: cfg.AzureSDKCredential, + azureSDKClientOpt: cfg.AzureSDKClientOption, + outdir: cfg.OutputDir, + outputFileNames: outputFileNames, + resourceClient: resClient, + providerVersion: cfg.ProviderVersion, + devProvider: cfg.DevProvider, + backendType: cfg.BackendType, + backendConfig: cfg.BackendConfig, + providerConfig: cfg.ProviderConfig, + providerName: cfg.ProviderName, + fullConfig: cfg.FullConfig, + parallelism: cfg.Parallelism, + generateImportFile: cfg.GenerateImportBlock, + hclOnly: cfg.HCLOnly, + tfclient: cfg.TFClient, moduleAddr: moduleAddr, moduleDir: moduleDir, @@ -402,18 +403,7 @@ func (meta baseMeta) ExportResourceMapping(ctx context.Context, l ImportList) er return fmt.Errorf("writing the resource mapping to %s: %v", oMapFile, err) } - // Only generate import.tf when the current using terraform supports plannable import - var supportPlannableImport bool - if meta.tf == nil { - supportPlannableImport = true - } else { - ver, _, err := meta.tf.Version(ctx, true) - if err != nil { - return fmt.Errorf("getting terraform version") - } - supportPlannableImport = ver.GreaterThanOrEqual(version.Must(version.NewVersion("v1.5.0"))) - } - if supportPlannableImport { + if meta.generateImportFile { f := hclwrite.NewFile() body := f.Body() for _, item := range l { @@ -433,6 +423,7 @@ func (meta baseMeta) ExportResourceMapping(ctx context.Context, l ImportList) er return fmt.Errorf("writing the import block to %s: %v", oImportFile, err) } } + return nil } diff --git a/internal/test/query/query_test.go b/internal/test/query/query_test.go index d4daeeb..afd5545 100644 --- a/internal/test/query/query_test.go +++ b/internal/test/query/query_test.go @@ -97,6 +97,7 @@ resource "azurerm_subnet" "test" { BackendType: "local", DevProvider: true, Parallelism: 1, + ProviderName: "azurerm", }, ResourceNamePattern: "res-", ARGPredicate: fmt.Sprintf(`resourceGroup =~ "%s" and type =~ "microsoft.network/virtualnetworks"`, d.RandomRgName()), diff --git a/internal/test/resmap/e2e_cases_test.go b/internal/test/resmap/e2e_cases_test.go index 1861407..1f87670 100644 --- a/internal/test/resmap/e2e_cases_test.go +++ b/internal/test/resmap/e2e_cases_test.go @@ -80,6 +80,7 @@ func runCase(t *testing.T, d test.Data, c cases.Case) { BackendType: "local", DevProvider: true, Parallelism: 1, + ProviderName: "azurerm", }, MappingFile: mapFile, }, diff --git a/internal/test/resource/e2e_cases_test.go b/internal/test/resource/e2e_cases_test.go index a0d7d18..d4d29ed 100644 --- a/internal/test/resource/e2e_cases_test.go +++ b/internal/test/resource/e2e_cases_test.go @@ -78,6 +78,7 @@ func runCase(t *testing.T, d test.Data, c cases.Case) { BackendType: "local", DevProvider: true, Parallelism: 1, + ProviderName: "azurerm", }, ResourceId: rctx.AzureId, TFResourceName: fmt.Sprintf("res-%d", idx), diff --git a/internal/test/resourcegroup/append_test.go b/internal/test/resourcegroup/append_test.go index 2d8a94f..a0a415b 100644 --- a/internal/test/resourcegroup/append_test.go +++ b/internal/test/resourcegroup/append_test.go @@ -91,6 +91,7 @@ resource "azurerm_resource_group" "test3" { BackendType: "local", DevProvider: true, Parallelism: 1, + ProviderName: "azurerm", }, ResourceNamePattern: "t1", }, diff --git a/internal/test/resourcegroup/hcl_only_test.go b/internal/test/resourcegroup/hcl_only_test.go index 4f67374..0643549 100644 --- a/internal/test/resourcegroup/hcl_only_test.go +++ b/internal/test/resourcegroup/hcl_only_test.go @@ -97,6 +97,7 @@ func runHCLOnly(t *testing.T, d test.Data, c cases.Case) { DevProvider: true, Parallelism: 10, HCLOnly: true, + ProviderName: "azurerm", }, ResourceGroupName: d.RandomRgName(), ResourceNamePattern: "res-", diff --git a/internal/test/resourcegroup/module_test.go b/internal/test/resourcegroup/module_test.go index ba701b4..0d347d4 100644 --- a/internal/test/resourcegroup/module_test.go +++ b/internal/test/resourcegroup/module_test.go @@ -118,6 +118,8 @@ module "sub-module" { BackendType: "local", Parallelism: 1, ModulePath: "", // Import to the root module + ProviderName: "azurerm", + GenerateImportBlock: false, }, }, PlainUI: true, diff --git a/main.go b/main.go index cecf5c7..d8e6bc2 100644 --- a/main.go +++ b/main.go @@ -229,6 +229,12 @@ func main() { Usage: `The path of the module (e.g. "module1.module2") where the resources will be imported and config generated. Note that only modules whose "source" is local path is supported. Defaults to the root module.`, Destination: &flagset.flagModulePath, }, + &cli.BoolFlag{ + Name: "generate-import-block", + EnvVars: []string{"AZTFEXPORT_GENERATE_IMPORT_BLOCK"}, + Usage: `Whether to generate the import.tf that contains the "import" blocks for the Terraform official plannable importing`, + Destination: &flagset.flagGenerateImportBlock, + }, &cli.StringFlag{ Name: "log-path", EnvVars: []string{"AZTFEXPORT_LOG_PATH"}, diff --git a/pkg/config/config.go b/pkg/config/config.go index 9d245bb..678bd14 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -63,6 +63,8 @@ type CommonConfig struct { TFClient tfclient.Client // TelemetryClient is a client to send telemetry TelemetryClient telemetry.Client + // GenerateImportBlock controls whether the export process ends up with a import.tf file that contains the "import" blocks + GenerateImportBlock bool } type Config struct {