Skip to content
Open
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
8 changes: 4 additions & 4 deletions flag.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ type FlagSet struct {
flagProviderName string
flagBackendType string
flagBackendConfig cli.StringSlice
flagFullConfig bool
flagConfigMode string
flagMaskSensitive bool
flagParallelism int
flagContinue bool
Expand Down Expand Up @@ -144,8 +144,8 @@ func (flag FlagSet) DescribeCLI(mode Mode) string {
if flag.flagBackendType != "" {
args = append(args, "--backend-type="+flag.flagBackendType)
}
if flag.flagFullConfig {
args = append(args, "--full-properties=true")
if flag.flagConfigMode != "" && flag.flagConfigMode != string(config.ConfigModeMinimal) {
args = append(args, "--config-mode="+flag.flagConfigMode)
}
if flag.flagMaskSensitive {
args = append(args, "--mask-sensitive=true")
Expand Down Expand Up @@ -458,7 +458,7 @@ func (f FlagSet) BuildCommonConfig() (config.CommonConfig, error) {
ContinueOnError: f.flagContinue,
BackendType: f.flagBackendType,
BackendConfig: f.flagBackendConfig.Value(),
FullConfig: f.flagFullConfig,
ConfigMode: config.ConfigMode(f.flagConfigMode),
MaskSensitive: f.flagMaskSensitive,
Parallelism: f.flagParallelism,
HCLOnly: f.flagHCLOnly,
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ require (
github.com/magodo/spinner v0.0.0-20240524082745-3a2305db1bdc
github.com/magodo/terraform-client-go v0.0.0-20240804032252-6d93a97fabb2
github.com/magodo/textinput v0.0.0-20210913072708-7d24f2b4b0c0
github.com/magodo/tfadd v0.10.1-0.20260402010906-8f7ab2866ec6
github.com/magodo/tfadd v0.10.1-0.20260625074521-bfdd14b3d25b
github.com/magodo/tfmerge v0.0.0-20221214062955-f52e46d03402
github.com/magodo/tfstate v0.0.0-20241016043929-2c95177bf0e6
github.com/magodo/workerpool v0.0.0-20240524082508-11838001bc35
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -272,8 +272,8 @@ github.com/magodo/terraform-client-go v0.0.0-20240804032252-6d93a97fabb2 h1:X2ph
github.com/magodo/terraform-client-go v0.0.0-20240804032252-6d93a97fabb2/go.mod h1:dzTs6Qwy8/VUWYMQ+Vo9gMXe5uOVbfCw/1ovE3g5q1E=
github.com/magodo/textinput v0.0.0-20210913072708-7d24f2b4b0c0 h1:aNtr4iNv/tex2t8W1u3scAoNHEnFlTKhNNHOpYStqbs=
github.com/magodo/textinput v0.0.0-20210913072708-7d24f2b4b0c0/go.mod h1:MqYhNP+PC386Bjsx5piZe7T4vDm5QIPv8b1RU0prVnU=
github.com/magodo/tfadd v0.10.1-0.20260402010906-8f7ab2866ec6 h1:aD83e/Lol5MVEE3PosjacwADZjc1kBDD4YPzUut2UxE=
github.com/magodo/tfadd v0.10.1-0.20260402010906-8f7ab2866ec6/go.mod h1:Ul9tfUbNokUeWnT/xzwvqxxma7mJRMG5pUjz2H/cY1w=
github.com/magodo/tfadd v0.10.1-0.20260625074521-bfdd14b3d25b h1:xcv6g2IXUVURA5T3wgJTPPJgn3aOShnn1+AsXMCuWVw=
github.com/magodo/tfadd v0.10.1-0.20260625074521-bfdd14b3d25b/go.mod h1:Ul9tfUbNokUeWnT/xzwvqxxma7mJRMG5pUjz2H/cY1w=
github.com/magodo/tfmerge v0.0.0-20221214062955-f52e46d03402 h1:RyaR4VE7hoR9AyoVH414cpM8V63H4rLe2aZyKdoDV1w=
github.com/magodo/tfmerge v0.0.0-20221214062955-f52e46d03402/go.mod h1:ssV++b4DH33rsD592bvpS4Peng3ZfdGNZbFgCDkCfj8=
github.com/magodo/tfpluginschema v0.0.0-20240902090353-0525d7d8c1c2 h1:Unxx8WLxzSxINnq7hItp4cXD7drihgfPltTd91efoBo=
Expand Down
58 changes: 52 additions & 6 deletions internal/meta/base_meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ type baseMeta struct {
providerConfig map[string]cty.Value

// tfadd options
fullConfig bool
configMode config.ConfigMode
maskSensitive bool

parallelism int
Expand Down Expand Up @@ -287,6 +287,22 @@ func NewBaseMeta(cfg config.CommonConfig) (*baseMeta, error) {
excludeAzureResources = append(excludeAzureResources, *re)
}

// Resolve ConfigMode.
configMode := cfg.ConfigMode
switch configMode {
case "":
configMode = config.ConfigModeMinimal
case config.ConfigModeMinimal, config.ConfigModeLossless, config.ConfigModeFull:
// ok
default:
return nil, fmt.Errorf("invalid ConfigMode %q: must be one of %q, %q, %q",
cfg.ConfigMode,
config.ConfigModeMinimal,
config.ConfigModeLossless,
config.ConfigModeFull,
)
}

meta := &baseMeta{
logger: cfg.Logger,
subscriptionId: cfg.SubscriptionId,
Expand All @@ -301,7 +317,7 @@ func NewBaseMeta(cfg config.CommonConfig) (*baseMeta, error) {
backendConfig: cfg.BackendConfig,
providerConfig: providerConfig,
providerName: cfg.ProviderName,
fullConfig: cfg.FullConfig,
configMode: configMode,
maskSensitive: cfg.MaskSensitive,
parallelism: cfg.Parallelism,
preImportHook: cfg.PreImportHook,
Expand Down Expand Up @@ -1029,6 +1045,37 @@ func (meta *baseMeta) importItem_notf(ctx context.Context, item *ImportItem, imp
return
}

// tfaddOptions translates the configured ConfigMode (plus the provider in use)
// into the set of tfadd options that drive trimming behaviour.
func (meta baseMeta) tfaddOptions() []tfadd.OptionSetter {
opts := []tfadd.OptionSetter{
tfadd.MaskSenstitive(meta.maskSensitive),
}

switch meta.configMode {
case config.ConfigModeFull:
opts = append(opts, tfadd.Full(true))
case config.ConfigModeLossless:
opts = append(opts,
tfadd.KeepOC(true),
// The azurerm provider currently uses Terraform Plugin SDKv2, which tolerates
// the mismatch between null and zero values, so zero values can be safely
// trimmed.
// The azapi provider uses Plugin Framework, which does NOT tolerate
// that mismatch, so zero values must be kept to produce a semantically
// equivalent config.
tfadd.KeepZero(meta.useAzAPI()),
)
case config.ConfigModeMinimal:
opts = append(opts,
// Same here.
tfadd.KeepZero(meta.useAzAPI()),
)
}

return opts
}

func (meta baseMeta) stateToConfig(ctx context.Context, list ImportList) (ConfigInfos, error) {
var out []ConfigInfo
var bs [][]byte
Expand All @@ -1039,6 +1086,7 @@ func (meta baseMeta) stateToConfig(ctx context.Context, list ImportList) (Config
if meta.useAzAPI() {
providerName = "registry.terraform.io/azure/azapi"
}
tfaddOpts := meta.tfaddOptions()

if meta.tfclient != nil {
for _, item := range importedList {
Expand All @@ -1059,8 +1107,7 @@ func (meta baseMeta) stateToConfig(ctx context.Context, list ImportList) (Config
ProviderName: providerName,
Value: item.State,
},
tfadd.Full(meta.fullConfig),
tfadd.MaskSenstitive(meta.maskSensitive),
tfaddOpts...,
)
if err != nil {
return nil, fmt.Errorf("generating state for resource %s: %v", item.TFAddr, err)
Expand All @@ -1078,7 +1125,7 @@ func (meta baseMeta) stateToConfig(ctx context.Context, list ImportList) (Config
}

var err error
bs, err = tfadd.StateForTargets(ctx, meta.tf, addrs, tfadd.Full(meta.fullConfig), tfadd.MaskSenstitive(meta.maskSensitive))
bs, err = tfadd.StateForTargets(ctx, meta.tf, addrs, tfaddOpts...)
if err != nil {
return nil, fmt.Errorf("converting terraform state to config: %w", err)
}
Expand Down Expand Up @@ -1222,4 +1269,3 @@ func appendToFile(path, content string) error {
_, err = f.WriteString(content)
return err
}

12 changes: 6 additions & 6 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,12 +155,12 @@ func main() {
Usage: "The Terraform backend config",
Destination: &flagset.flagBackendConfig,
},
&cli.BoolFlag{
Name: "full-properties",
EnvVars: []string{"AZTFEXPORT_FULL_PROPERTIES"},
Usage: "Includes all non-computed properties in the Terraform configuration. This may require manual modifications to produce a valid config",
Value: false,
Destination: &flagset.flagFullConfig,
&cli.StringFlag{
Name: "config-mode",
EnvVars: []string{"AZTFEXPORT_CONFIG_MODE"},
Usage: `The trimming mode for the generated Terraform config. Can be one of "minimal" (most aggressive; trims zero values, schema defaults and Optional+Computed attributes), "lossless" (keeps Optional+Computed attributes so the config matches the live state) and "full" (keeps every property; may require manual edits to be valid)`,
Value: string(config.ConfigModeMinimal),
Destination: &flagset.flagConfigMode,
},
&cli.BoolFlag{
Name: "mask-sensitive",
Expand Down
25 changes: 23 additions & 2 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,27 @@ type OutputFileNames struct {
ImportBlockFileName string
}

// ConfigMode controls how aggressively the generated Terraform configuration
// trims properties read back from the resource state.
type ConfigMode string

const (
// ConfigModeMinimal generates the smallest possible config by removing
// zero values, schema defaults, and Optional+Computed
// attributes/blocks.
ConfigModeMinimal ConfigMode = "minimal"

// ConfigModeLossless keeps Optional+Computed attributes/blocks (so the
// generated config matches the live state), while still removing schema
// defaults and (for SDKv2 providers) zero values that can be safely
// dropped without changing semantics.
ConfigModeLossless ConfigMode = "lossless"

// ConfigModeFull keeps every property, including zero values, schema
// defaults, and Optional+Computed attributes/blocks.
ConfigModeFull ConfigMode = "full"
)

type CommonConfig struct {
Logger *slog.Logger
// AuthConfig specifies the authentication config for provider
Expand Down Expand Up @@ -73,8 +94,8 @@ type CommonConfig struct {
// This is not used directly by aztfexport as the provider configs can be set by environment variable already.
// While it is useful for module users that want support multi-users scenarios in one process (in which case changing env vars affect the whole process).
ProviderConfig map[string]cty.Value
// FullConfig specifies whether to export all (non computed-only) Terarform properties when generating TF configs.
FullConfig bool
// ConfigMode controls how aggressively the generated TF config is trimmed. Defaults to ConfigModeMinimal.
ConfigMode ConfigMode
// MaskSensitive specifies whether to mask sensitive attributes when generating TF configs.
MaskSensitive bool
// Parallelism specifies the parallelism for the process
Expand Down
Loading