From da100649af2a48b1cade95d2c7b2a7e92442b676 Mon Sep 17 00:00:00 2001 From: xescugc Date: Tue, 16 May 2023 14:11:37 +0200 Subject: [PATCH] cycloid fixes --- {internal/addrs => addrs}/check.go | 2 +- .../addrs => addrs}/checkablekind_string.go | 0 {internal/addrs => addrs}/checktype_string.go | 0 {internal/addrs => addrs}/count_attr.go | 0 {internal/addrs => addrs}/doc.go | 0 {internal/addrs => addrs}/for_each_attr.go | 0 {internal/addrs => addrs}/input_variable.go | 0 {internal/addrs => addrs}/instance_key.go | 0 .../addrs => addrs}/instance_key_test.go | 0 {internal/addrs => addrs}/local_value.go | 0 {internal/addrs => addrs}/map.go | 0 {internal/addrs => addrs}/map_test.go | 0 {internal/addrs => addrs}/module.go | 0 {internal/addrs => addrs}/module_call.go | 0 {internal/addrs => addrs}/module_instance.go | 2 +- .../addrs => addrs}/module_instance_test.go | 0 {internal/addrs => addrs}/module_package.go | 0 {internal/addrs => addrs}/module_source.go | 2 +- .../addrs => addrs}/module_source_test.go | 0 {internal/addrs => addrs}/module_test.go | 0 {internal/addrs => addrs}/move_endpoint.go | 2 +- .../addrs => addrs}/move_endpoint_kind.go | 0 .../addrs => addrs}/move_endpoint_module.go | 2 +- .../move_endpoint_module_test.go | 2 +- .../addrs => addrs}/move_endpoint_test.go | 0 {internal/addrs => addrs}/moveable.go | 0 .../moveendpointkind_string.go | 0 {internal/addrs => addrs}/output_value.go | 2 +- .../addrs => addrs}/output_value_test.go | 0 {internal/addrs => addrs}/parse_ref.go | 2 +- {internal/addrs => addrs}/parse_ref_test.go | 2 +- {internal/addrs => addrs}/parse_target.go | 2 +- .../addrs => addrs}/parse_target_test.go | 2 +- {internal/addrs => addrs}/path_attr.go | 0 {internal/addrs => addrs}/provider.go | 2 +- {internal/addrs => addrs}/provider_config.go | 2 +- .../addrs => addrs}/provider_config_test.go | 0 {internal/addrs => addrs}/provider_test.go | 0 {internal/addrs => addrs}/referenceable.go | 0 {internal/addrs => addrs}/resource.go | 0 {internal/addrs => addrs}/resource_phase.go | 0 {internal/addrs => addrs}/resource_test.go | 0 .../addrs => addrs}/resourcemode_string.go | 0 {internal/addrs => addrs}/self.go | 0 {internal/addrs => addrs}/set.go | 0 {internal/addrs => addrs}/target_test.go | 0 {internal/addrs => addrs}/targetable.go | 0 {internal/addrs => addrs}/terraform_attr.go | 0 {internal/addrs => addrs}/unique_key.go | 0 {internal/addrs => addrs}/unique_key_test.go | 0 {internal/backend => backend}/backend.go | 26 +- {internal/backend => backend}/backend_test.go | 0 {internal/backend => backend}/cli.go | 4 +- .../init/deprecate_test.go | 2 +- {internal/backend => backend}/init/init.go | 30 +- .../backend => backend}/init/init_test.go | 0 .../backend => backend}/local/backend.go | 14 +- .../local/backend_apply.go | 18 +- .../local/backend_apply_test.go | 30 +- .../local/backend_local.go | 14 +- .../local/backend_local_test.go | 30 +- .../backend => backend}/local/backend_plan.go | 16 +- .../local/backend_plan_test.go | 26 +- .../local/backend_refresh.go | 10 +- .../local/backend_refresh_test.go | 24 +- .../backend => backend}/local/backend_test.go | 6 +- {internal/backend => backend}/local/cli.go | 2 +- .../backend => backend}/local/hook_state.go | 6 +- .../local/hook_state_test.go | 4 +- .../backend => backend}/local/local_test.go | 2 +- .../local/testdata/apply-empty/hello.txt | 0 .../local/testdata/apply-error/main.tf | 0 .../local/testdata/apply/main.tf | 0 .../local/testdata/destroy-with-ds/main.tf | 0 .../local/testdata/empty/.gitignore | 0 .../local/testdata/invalid/invalid.tf | 0 .../local/testdata/plan-cbd/main.tf | 0 .../plan-module-outputs-changed/main.tf | 0 .../plan-module-outputs-changed/mod/main.tf | 0 .../testdata/plan-outputs-changed/main.tf | 0 .../plan-outputs-changed/submodule/main.tf | 0 .../local/testdata/plan/main.tf | 0 .../testdata/refresh-provider-config/main.tf | 0 .../local/testdata/refresh-var-unset/main.tf | 0 .../local/testdata/refresh/main.tf | 0 .../backend => backend}/local/testing.go | 14 +- .../backend => backend}/operation_type.go | 0 .../operationtype_string.go | 0 .../remote-state/azure/arm_client.go | 2 +- .../remote-state/azure/backend.go | 4 +- .../remote-state/azure/backend_state.go | 8 +- .../remote-state/azure/backend_test.go | 4 +- .../remote-state/azure/client.go | 4 +- .../remote-state/azure/client_test.go | 6 +- .../remote-state/azure/helpers_test.go | 0 .../remote-state/azure/sender.go | 2 +- .../remote-state/consul/backend.go | 4 +- .../remote-state/consul/backend_state.go | 8 +- .../remote-state/consul/backend_test.go | 2 +- .../remote-state/consul/client.go | 4 +- .../remote-state/consul/client_test.go | 6 +- .../remote-state/cos/backend.go | 4 +- .../remote-state/cos/backend_state.go | 8 +- .../remote-state/cos/backend_test.go | 4 +- .../remote-state/cos/client.go | 4 +- .../remote-state/cos/transport.go | 0 .../remote-state/gcs/backend.go | 6 +- .../remote-state/gcs/backend_state.go | 8 +- .../remote-state/gcs/backend_test.go | 6 +- .../remote-state/gcs/client.go | 4 +- .../remote-state/http/backend.go | 10 +- .../remote-state/http/backend_test.go | 4 +- .../remote-state/http/client.go | 4 +- .../remote-state/http/client_test.go | 2 +- .../remote-state/http/mock_server_test.go | 0 .../remote-state/http/server_test.go | 8 +- .../http/testdata/certs/ca.cert.pem | 0 .../remote-state/http/testdata/certs/ca.key | 0 .../http/testdata/certs/client.crt | 0 .../http/testdata/certs/client.csr | 0 .../http/testdata/certs/client.key | 0 .../http/testdata/certs/server.crt | 0 .../http/testdata/certs/server.csr | 0 .../http/testdata/certs/server.key | 0 .../remote-state/http/testdata/gencerts.sh | 0 .../remote-state/inmem/backend.go | 10 +- .../remote-state/inmem/backend_test.go | 8 +- .../remote-state/inmem/client.go | 4 +- .../remote-state/inmem/client_test.go | 4 +- .../remote-state/kubernetes/backend.go | 4 +- .../remote-state/kubernetes/backend_state.go | 8 +- .../remote-state/kubernetes/backend_test.go | 4 +- .../remote-state/kubernetes/client.go | 4 +- .../remote-state/kubernetes/client_test.go | 6 +- .../remote-state/oss/backend.go | 4 +- .../remote-state/oss/backend_state.go | 8 +- .../remote-state/oss/backend_test.go | 4 +- .../remote-state/oss/client.go | 4 +- .../remote-state/oss/client_test.go | 8 +- .../remote-state/pg/backend.go | 4 +- .../remote-state/pg/backend_state.go | 8 +- .../remote-state/pg/backend_test.go | 6 +- .../remote-state/pg/client.go | 4 +- .../remote-state/pg/client_test.go | 4 +- .../remote-state/s3/backend.go | 6 +- .../remote-state/s3/backend_state.go | 8 +- .../remote-state/s3/backend_test.go | 8 +- .../remote-state/s3/client.go | 4 +- .../remote-state/s3/client_test.go | 8 +- .../backend => backend}/remote/backend.go | 16 +- .../remote/backend_apply.go | 8 +- .../remote/backend_apply_test.go | 26 +- .../remote/backend_common.go | 8 +- .../remote/backend_context.go | 10 +- .../remote/backend_context_test.go | 20 +- .../remote/backend_plan.go | 8 +- .../remote/backend_plan_test.go | 26 +- .../remote/backend_state.go | 8 +- .../remote/backend_state_test.go | 10 +- .../remote/backend_test.go | 6 +- {internal/backend => backend}/remote/cli.go | 2 +- .../backend => backend}/remote/colorize.go | 0 .../backend => backend}/remote/remote_test.go | 2 +- .../remote/testdata/apply-destroy/apply.log | 0 .../remote/testdata/apply-destroy/main.tf | 0 .../remote/testdata/apply-destroy/plan.log | 0 .../remote/testdata/apply-no-changes/main.tf | 0 .../remote/testdata/apply-no-changes/plan.log | 0 .../testdata/apply-no-changes/policy.log | 0 .../testdata/apply-policy-hard-failed/main.tf | 0 .../apply-policy-hard-failed/plan.log | 0 .../apply-policy-hard-failed/policy.log | 0 .../testdata/apply-policy-passed/apply.log | 0 .../testdata/apply-policy-passed/main.tf | 0 .../testdata/apply-policy-passed/plan.log | 0 .../testdata/apply-policy-passed/policy.log | 0 .../apply-policy-soft-failed/apply.log | 0 .../testdata/apply-policy-soft-failed/main.tf | 0 .../apply-policy-soft-failed/plan.log | 0 .../apply-policy-soft-failed/policy.log | 0 .../remote/testdata/apply-variables/apply.log | 0 .../remote/testdata/apply-variables/main.tf | 0 .../remote/testdata/apply-variables/plan.log | 0 .../remote/testdata/apply-with-error/main.tf | 0 .../remote/testdata/apply-with-error/plan.log | 0 .../remote/testdata/apply/apply.log | 0 .../remote/testdata/apply/main.tf | 0 .../remote/testdata/apply/plan.log | 0 .../remote/testdata/empty/.gitignore | 0 .../testdata/plan-cost-estimation/ce.log | 0 .../plan-cost-estimation/cost-estimate.log | 0 .../testdata/plan-cost-estimation/main.tf | 0 .../testdata/plan-cost-estimation/plan.log | 0 .../remote/testdata/plan-long-line/main.tf | 0 .../remote/testdata/plan-long-line/plan.log | 0 .../remote/testdata/plan-no-changes/main.tf | 0 .../remote/testdata/plan-no-changes/plan.log | 0 .../testdata/plan-no-changes/policy.log | 0 .../testdata/plan-policy-hard-failed/main.tf | 0 .../testdata/plan-policy-hard-failed/plan.log | 0 .../plan-policy-hard-failed/policy.log | 0 .../testdata/plan-policy-passed/main.tf | 0 .../testdata/plan-policy-passed/plan.log | 0 .../testdata/plan-policy-passed/policy.log | 0 .../testdata/plan-policy-soft-failed/main.tf | 0 .../testdata/plan-policy-soft-failed/plan.log | 0 .../plan-policy-soft-failed/policy.log | 0 .../remote/testdata/plan-variables/main.tf | 0 .../remote/testdata/plan-variables/plan.log | 0 .../remote/testdata/plan-with-error/main.tf | 0 .../remote/testdata/plan-with-error/plan.log | 0 .../terraform/main.tf | 0 .../terraform/plan.log | 0 .../remote/testdata/plan/main.tf | 0 .../remote/testdata/plan/plan.log | 0 .../remote/testdata/variables/main.tf | 0 .../backend => backend}/remote/testing.go | 20 +- {internal/backend => backend}/testing.go | 12 +- .../backend => backend}/unparsed_value.go | 6 +- .../unparsed_value_test.go | 6 +- .../builtin => builtin}/providers/README | 0 .../providers/terraform/data_source_state.go | 12 +- .../terraform/data_source_state_test.go | 8 +- .../providers/terraform/provider.go | 2 +- .../providers/terraform/provider_test.go | 2 +- .../providers/terraform/resource_data.go | 6 +- .../providers/terraform/resource_data_test.go | 2 +- .../terraform/testdata/basic.tfstate | 0 .../testdata/complex_outputs.tfstate | 0 .../terraform/testdata/empty.tfstate | 0 .../terraform/testdata/null_outputs.tfstate | 0 .../provisioners/file/resource_provisioner.go | 8 +- .../file/resource_provisioner_test.go | 2 +- .../local-exec/resource_provisioner.go | 6 +- .../local-exec/resource_provisioner_test.go | 2 +- .../remote-exec/resource_provisioner.go | 10 +- .../remote-exec/resource_provisioner_test.go | 6 +- .../remote-exec/testdata/script1.sh | 0 checkpoint.go | 4 +- {internal/checks => checks}/doc.go | 0 {internal/checks => checks}/state.go | 4 +- {internal/checks => checks}/state_init.go | 4 +- {internal/checks => checks}/state_report.go | 2 +- {internal/checks => checks}/state_test.go | 6 +- {internal/checks => checks}/status.go | 0 {internal/checks => checks}/status_string.go | 0 .../testdata/happypath/checks-happypath.tf | 0 .../happypath/child/checks-happypath-child.tf | 0 {internal/cloud => cloud}/backend.go | 16 +- {internal/cloud => cloud}/backend_apply.go | 10 +- .../cloud => cloud}/backend_apply_test.go | 26 +- {internal/cloud => cloud}/backend_cli.go | 4 +- {internal/cloud => cloud}/backend_colorize.go | 0 {internal/cloud => cloud}/backend_common.go | 10 +- {internal/cloud => cloud}/backend_context.go | 10 +- .../cloud => cloud}/backend_context_test.go | 20 +- {internal/cloud => cloud}/backend_plan.go | 8 +- .../cloud => cloud}/backend_plan_test.go | 26 +- .../cloud => cloud}/backend_refresh_test.go | 16 +- .../backend_taskStage_policyEvaluation.go | 0 ...backend_taskStage_policyEvaluation_test.go | 0 .../backend_taskStage_taskResults.go | 0 .../backend_taskStage_taskResults_test.go | 0 .../cloud => cloud}/backend_taskStages.go | 2 +- .../backend_taskStages_test.go | 0 {internal/cloud => cloud}/backend_test.go | 6 +- .../cloud => cloud}/cloud_integration.go | 2 +- {internal/cloud => cloud}/cloud_variables.go | 8 +- .../cloud => cloud}/cloud_variables_test.go | 8 +- .../configchangemode_string.go | 0 {internal/cloud => cloud}/e2e/README.md | 0 .../e2e/apply_auto_approve_test.go | 0 .../e2e/apply_no_input_flag_test.go | 0 .../e2e/backend_apply_before_init_test.go | 0 .../cloud => cloud}/e2e/env_variables_test.go | 0 {internal/cloud => cloud}/e2e/helper_test.go | 0 .../e2e/init_with_empty_tags_test.go | 0 {internal/cloud => cloud}/e2e/main_test.go | 2 +- .../e2e/migrate_state_multi_to_tfc_test.go | 0 ...igrate_state_remote_backend_to_tfc_test.go | 0 .../e2e/migrate_state_single_to_tfc_test.go | 0 .../e2e/migrate_state_tfc_to_other_test.go | 0 .../e2e/migrate_state_tfc_to_tfc_test.go | 0 .../cloud => cloud}/e2e/run_variables_test.go | 0 {internal/cloud => cloud}/errors.go | 2 +- {internal/cloud => cloud}/migration.go | 4 +- {internal/cloud => cloud}/migration_test.go | 4 +- {internal/cloud => cloud}/remote_test.go | 2 +- {internal/cloud => cloud}/state.go | 12 +- {internal/cloud => cloud}/state_test.go | 4 +- {internal/cloud => cloud}/testdata/.gitignore | 0 .../testdata/apply-destroy/apply.log | 0 .../testdata/apply-destroy/main.tf | 0 .../testdata/apply-destroy/plan.log | 0 .../testdata/apply-json-with-error/main.tf | 0 .../apply-json-with-error/plan-redacted.json | 0 .../testdata/apply-json-with-error/plan.log | 0 .../apply-json-with-outputs/apply.log | 0 .../testdata/apply-json-with-outputs/main.tf | 0 .../plan-redacted.json | 0 .../testdata/apply-json-with-outputs/plan.log | 0 .../apply.log | 0 .../apply-json-with-provisioner-error/main.tf | 0 .../plan-redacted.json | 0 .../plan.log | 0 .../apply-json-with-provisioner/apply.log | 0 .../apply-json-with-provisioner/main.tf | 0 .../plan-redacted.json | 0 .../apply-json-with-provisioner/plan.log | 0 .../testdata/apply-json/apply.log | 0 .../testdata/apply-json/main.tf | 0 .../testdata/apply-json/plan-redacted.json | 0 .../testdata/apply-json/plan.log | 0 .../testdata/apply-no-changes/main.tf | 0 .../testdata/apply-no-changes/plan.log | 0 .../testdata/apply-no-changes/policy.log | 0 .../testdata/apply-policy-hard-failed/main.tf | 0 .../apply-policy-hard-failed/plan.log | 0 .../apply-policy-hard-failed/policy.log | 0 .../testdata/apply-policy-passed/apply.log | 0 .../testdata/apply-policy-passed/main.tf | 0 .../testdata/apply-policy-passed/plan.log | 0 .../testdata/apply-policy-passed/policy.log | 0 .../apply-policy-soft-failed/apply.log | 0 .../testdata/apply-policy-soft-failed/main.tf | 0 .../apply-policy-soft-failed/plan.log | 0 .../apply-policy-soft-failed/policy.log | 0 .../testdata/apply-variables/apply.log | 0 .../testdata/apply-variables/main.tf | 0 .../testdata/apply-variables/plan.log | 0 .../testdata/apply-with-error/main.tf | 0 .../testdata/apply-with-error/plan.log | 0 .../cloud => cloud}/testdata/apply/apply.log | 0 .../cloud => cloud}/testdata/apply/main.tf | 0 .../cloud => cloud}/testdata/apply/plan.log | 0 .../cloud => cloud}/testdata/empty/.gitignore | 0 .../testdata/plan-cost-estimation/ce.log | 0 .../plan-cost-estimation/cost-estimate.log | 0 .../testdata/plan-cost-estimation/main.tf | 0 .../testdata/plan-cost-estimation/plan.log | 0 .../testdata/plan-json-basic/main.tf | 0 .../plan-json-basic/plan-redacted.json | 0 .../testdata/plan-json-basic/plan.log | 0 .../testdata/plan-json-error/main.tf | 0 .../plan-json-error/plan-redacted.json | 0 .../testdata/plan-json-error/plan.log | 0 .../testdata/plan-json-full/main.tf | 0 .../plan-json-full/plan-redacted.json | 0 .../testdata/plan-json-full/plan.log | 0 .../testdata/plan-long-line/main.tf | 0 .../testdata/plan-long-line/plan.log | 0 .../testdata/plan-no-changes/main.tf | 0 .../testdata/plan-no-changes/plan.log | 0 .../testdata/plan-no-changes/policy.log | 0 .../testdata/plan-policy-hard-failed/main.tf | 0 .../testdata/plan-policy-hard-failed/plan.log | 0 .../plan-policy-hard-failed/policy.log | 0 .../testdata/plan-policy-passed/main.tf | 0 .../testdata/plan-policy-passed/plan.log | 0 .../testdata/plan-policy-passed/policy.log | 0 .../testdata/plan-policy-soft-failed/main.tf | 0 .../testdata/plan-policy-soft-failed/plan.log | 0 .../plan-policy-soft-failed/policy.log | 0 .../testdata/plan-variables/main.tf | 0 .../testdata/plan-variables/plan.log | 0 .../testdata/plan-with-error/main.tf | 0 .../testdata/plan-with-error/plan.log | 0 .../terraform/main.tf | 0 .../terraform/plan.log | 0 .../cloud => cloud}/testdata/plan/main.tf | 0 .../cloud => cloud}/testdata/plan/plan.log | 0 .../cloud => cloud}/testdata/refresh/main.tf | 0 .../testdata/variables/main.tf | 0 {internal/cloud => cloud}/testing.go | 18 +- {internal/cloud => cloud}/tfe_client_mock.go | 2 +- {internal/command => command}/apply.go | 10 +- .../command => command}/apply_destroy_test.go | 10 +- {internal/command => command}/apply_test.go | 16 +- .../command => command}/arguments/apply.go | 4 +- .../arguments/apply_test.go | 4 +- .../command => command}/arguments/default.go | 0 .../command => command}/arguments/extended.go | 6 +- .../command => command}/arguments/flags.go | 0 .../command => command}/arguments/output.go | 2 +- .../arguments/output_test.go | 2 +- .../command => command}/arguments/plan.go | 2 +- .../arguments/plan_test.go | 4 +- .../command => command}/arguments/refresh.go | 2 +- .../arguments/refresh_test.go | 2 +- .../command => command}/arguments/show.go | 2 +- .../arguments/show_test.go | 2 +- .../command => command}/arguments/test.go | 2 +- .../arguments/test_test.go | 2 +- .../command => command}/arguments/types.go | 0 .../command => command}/arguments/validate.go | 2 +- .../arguments/validate_test.go | 2 +- .../command => command}/arguments/view.go | 0 .../arguments/view_test.go | 0 {internal/command => command}/autocomplete.go | 0 .../command => command}/autocomplete_test.go | 0 {internal/command => command}/cli_ui.go | 0 {internal/command => command}/cli_ui_test.go | 0 .../cliconfig/cliconfig.go | 2 +- .../cliconfig/cliconfig_test.go | 2 +- .../cliconfig/config_unix.go | 0 .../cliconfig/config_windows.go | 0 .../cliconfig/credentials.go | 6 +- .../cliconfig/credentials_test.go | 0 .../cliconfig/provider_installation.go | 6 +- .../cliconfig/provider_installation_test.go | 4 +- .../cliconfig/testdata/config | 0 .../cliconfig/testdata/config-env | 0 .../cliconfig/testdata/credentials | 0 .../cliconfig/testdata/hosts | 0 .../cliconfig/testdata/provider-installation | 0 .../testdata/provider-installation-errors | 0 .../testdata/provider-installation.json | 0 .../clistate/local_state.go | 4 +- .../clistate/local_state_lock_unix.go | 0 .../clistate/local_state_lock_windows.go | 0 .../command => command}/clistate/state.go | 8 +- .../clistate/state_test.go | 8 +- {internal/command => command}/command.go | 0 {internal/command => command}/command_test.go | 46 +- {internal/command => command}/console.go | 12 +- .../console_interactive.go | 2 +- .../console_interactive_solaris.go | 2 +- {internal/command => command}/console_test.go | 4 +- .../command => command}/e2etest/.gitignore | 0 .../e2etest/automation_test.go | 4 +- {internal/command => command}/e2etest/doc.go | 2 +- .../command => command}/e2etest/init_test.go | 2 +- .../command => command}/e2etest/main_test.go | 2 +- .../e2etest/make-archive.sh | 0 .../e2etest/module_archive_test.go | 2 +- .../e2etest/primary_test.go | 4 +- .../e2etest/provider_dev_test.go | 4 +- .../e2etest/provider_plugin_test.go | 8 +- .../e2etest/providers_mirror_test.go | 2 +- .../e2etest/providers_tamper_test.go | 4 +- .../e2etest/provisioner_plugin_test.go | 4 +- .../e2etest/provisioner_test.go | 2 +- .../e2etest/remote_state_test.go | 2 +- .../command => command}/e2etest/strip_ansi.go | 0 .../e2etest/terraform_test.go | 4 +- .../testdata/chdir-option/subdir/main.tf | 0 .../cliconfig.tfrc | 0 .../cliconfig.tfrc.json | 0 .../terraform-provider-happycloud_v1.2.0 | 0 .../custom-provider-install-method/main.tf | 0 .../e2etest/testdata/empty/.exists | 0 .../testdata/full-workflow-null/main.tf | 0 .../testdata/local-only-provider/main.tf | 0 .../terraform-provider-happycloud_v1.2.0 | 0 .../e2etest/testdata/module-archive/main.tf | 0 .../testdata/plugin-cache/.terraform.lock.hcl | 0 .../terraform-provider-template_v2.1.0_x4 | 0 .../e2etest/testdata/plugin-cache/main.tf | 0 .../provider-dev-override/pkgdir/.exists | 0 .../provider-dev-override.tf | 0 .../provider-not-found-non-default/main.tf | 0 .../testdata/provider-not-found/main.tf | 0 .../e2etest/testdata/provider-plugin/main.tf | 0 .../provider-tampering-base.tf | 0 .../testdata/provider-warnings/main.tf | 0 .../testdata/provisioner-plugin/main.tf | 0 .../e2etest/testdata/provisioner/main.tf | 0 .../testdata/template-provider/main.tf | 0 .../testdata/terraform-managed-data/main.tf | 0 .../testdata/terraform-provider/main.tf | 0 .../testdata/terraform-provider/test.tfstate | 0 .../.terraform.lock.hcl | 0 .../terraform-providers-mirror.tf | 0 .../terraform-providers-mirror.tf | 0 .../e2etest/testdata/test-provider/main.tf | 0 .../testdata/vendored-provider/main.tf | 0 .../os_arch/terraform-provider-null_v1.0.0 | 0 .../e2etest/unmanaged_test.go | 16 +- .../e2etest/version_test.go | 2 +- {internal/command => command}/flag_kv.go | 0 {internal/command => command}/flag_kv_test.go | 0 {internal/command => command}/fmt.go | 4 +- {internal/command => command}/fmt_test.go | 0 .../command => command}/format/diagnostic.go | 4 +- .../format/diagnostic_test.go | 6 +- {internal/command => command}/format/diff.go | 12 +- .../command => command}/format/diff_test.go | 10 +- .../format/difflanguage_string.go | 0 .../command => command}/format/format.go | 0 .../command => command}/format/object_id.go | 2 +- .../format/object_id_test.go | 2 +- {internal/command => command}/format/state.go | 10 +- .../command => command}/format/state_test.go | 10 +- .../command => command}/format/trivia.go | 0 {internal/command => command}/get.go | 2 +- {internal/command => command}/get_test.go | 0 {internal/command => command}/graph.go | 14 +- {internal/command => command}/graph_test.go | 6 +- {internal/command => command}/helper.go | 4 +- .../hook_module_install.go | 2 +- {internal/command => command}/import.go | 14 +- {internal/command => command}/import_test.go | 8 +- {internal/command => command}/init.go | 24 +- {internal/command => command}/init_test.go | 18 +- .../command => command}/jsonchecks/checks.go | 2 +- .../jsonchecks/checks_test.go | 6 +- .../command => command}/jsonchecks/doc.go | 0 .../command => command}/jsonchecks/objects.go | 2 +- .../command => command}/jsonchecks/status.go | 2 +- .../command => command}/jsonconfig/config.go | 10 +- .../jsonconfig/config_test.go | 0 .../command => command}/jsonconfig/doc.go | 0 .../jsonconfig/expression.go | 8 +- .../jsonconfig/expression_test.go | 2 +- .../command => command}/jsonformat/README.md | 0 .../jsonformat/collections/action.go | 2 +- .../jsonformat/collections/map.go | 4 +- .../jsonformat/collections/slice.go | 6 +- .../jsonformat/computed/diff.go | 2 +- .../jsonformat/computed/doc.go | 0 .../jsonformat/computed/renderers/block.go | 4 +- .../jsonformat/computed/renderers/blocks.go | 2 +- .../jsonformat/computed/renderers/json.go | 6 +- .../jsonformat/computed/renderers/list.go | 4 +- .../jsonformat/computed/renderers/map.go | 4 +- .../jsonformat/computed/renderers/object.go | 4 +- .../computed/renderers/primitive.go | 10 +- .../computed/renderers/renderer_test.go | 4 +- .../computed/renderers/sensitive.go | 4 +- .../computed/renderers/sensitive_block.go | 4 +- .../jsonformat/computed/renderers/set.go | 4 +- .../jsonformat/computed/renderers/string.go | 2 +- .../jsonformat/computed/renderers/testing.go | 4 +- .../computed/renderers/type_change.go | 2 +- .../jsonformat/computed/renderers/unknown.go | 4 +- .../jsonformat/computed/renderers/util.go | 6 +- .../command => command}/jsonformat/diff.go | 12 +- .../jsonformat/differ/attribute.go | 6 +- .../jsonformat/differ/block.go | 12 +- .../jsonformat/differ/differ.go | 4 +- .../jsonformat/differ/differ_test.go | 10 +- .../jsonformat/differ/list.go | 14 +- .../jsonformat/differ/map.go | 12 +- .../jsonformat/differ/object.go | 12 +- .../jsonformat/differ/output.go | 6 +- .../jsonformat/differ/primitive.go | 6 +- .../jsonformat/differ/sensitive.go | 10 +- .../jsonformat/differ/set.go | 14 +- .../jsonformat/differ/tuple.go | 8 +- .../jsonformat/differ/types.go | 0 .../jsonformat/differ/unknown.go | 8 +- .../jsonformat/jsondiff/diff.go | 8 +- .../jsonformat/jsondiff/types.go | 0 .../command => command}/jsonformat/plan.go | 14 +- .../jsonformat/plan_test.go | 26 +- .../jsonformat/renderer.go | 20 +- .../command => command}/jsonformat/state.go | 10 +- .../jsonformat/state_test.go | 20 +- .../structured/attribute_path/matcher.go | 0 .../structured/attribute_path/matcher_test.go | 0 .../jsonformat/structured/change.go | 10 +- .../jsonformat/structured/doc.go | 0 .../jsonformat/structured/map.go | 2 +- .../jsonformat/structured/sensitive.go | 4 +- .../jsonformat/structured/slice.go | 2 +- .../jsonformat/structured/unknown.go | 2 +- .../jsonfunction/function.go | 2 +- .../jsonfunction/function_test.go | 0 .../jsonfunction/parameter.go | 0 .../jsonfunction/parameter_test.go | 0 .../jsonfunction/return_type.go | 0 {internal/command => command}/jsonplan/doc.go | 0 .../command => command}/jsonplan/module.go | 0 .../command => command}/jsonplan/plan.go | 18 +- .../command => command}/jsonplan/plan_test.go | 4 +- .../command => command}/jsonplan/resource.go | 2 +- .../command => command}/jsonplan/values.go | 12 +- .../jsonplan/values_test.go | 8 +- .../jsonprovider/attribute.go | 2 +- .../jsonprovider/attribute_test.go | 2 +- .../command => command}/jsonprovider/block.go | 2 +- .../jsonprovider/block_test.go | 2 +- .../command => command}/jsonprovider/doc.go | 0 .../jsonprovider/provider.go | 2 +- .../jsonprovider/provider_test.go | 4 +- .../jsonprovider/schema.go | 2 +- .../jsonprovider/schema_test.go | 2 +- .../command => command}/jsonstate/doc.go | 0 .../command => command}/jsonstate/state.go | 12 +- .../jsonstate/state_test.go | 10 +- {internal/command => command}/login.go | 10 +- {internal/command => command}/login_test.go | 10 +- {internal/command => command}/logout.go | 4 +- {internal/command => command}/logout_test.go | 2 +- {internal/command => command}/meta.go | 36 +- {internal/command => command}/meta_backend.go | 26 +- .../meta_backend_migrate.go | 18 +- .../meta_backend_migrate_test.go | 0 .../command => command}/meta_backend_test.go | 22 +- {internal/command => command}/meta_config.go | 14 +- .../command => command}/meta_dependencies.go | 4 +- {internal/command => command}/meta_new.go | 2 +- .../command => command}/meta_providers.go | 20 +- {internal/command => command}/meta_test.go | 6 +- {internal/command => command}/meta_vars.go | 8 +- .../command => command}/metadata_command.go | 0 .../command => command}/metadata_functions.go | 4 +- .../metadata_functions_test.go | 0 {internal/command => command}/output.go | 8 +- {internal/command => command}/output_test.go | 4 +- {internal/command => command}/plan.go | 8 +- {internal/command => command}/plan_test.go | 18 +- {internal/command => command}/plugins.go | 14 +- {internal/command => command}/plugins_lock.go | 0 .../command => command}/plugins_lock_test.go | 0 {internal/command => command}/plugins_test.go | 0 {internal/command => command}/providers.go | 6 +- .../command => command}/providers_lock.go | 10 +- .../providers_lock_test.go | 6 +- .../command => command}/providers_mirror.go | 6 +- .../providers_mirror_test.go | 0 .../command => command}/providers_schema.go | 8 +- .../providers_schema_test.go | 6 +- .../command => command}/providers_test.go | 0 {internal/command => command}/push.go | 2 +- {internal/command => command}/refresh.go | 8 +- {internal/command => command}/refresh_test.go | 14 +- {internal/command => command}/show.go | 20 +- {internal/command => command}/show_test.go | 14 +- .../command => command}/state_command.go | 0 {internal/command => command}/state_list.go | 6 +- .../command => command}/state_list_test.go | 0 {internal/command => command}/state_meta.go | 10 +- {internal/command => command}/state_mv.go | 16 +- .../command => command}/state_mv_test.go | 4 +- {internal/command => command}/state_pull.go | 4 +- .../command => command}/state_pull_test.go | 0 {internal/command => command}/state_push.go | 14 +- .../command => command}/state_push_test.go | 6 +- .../state_replace_provider.go | 14 +- .../state_replace_provider_test.go | 4 +- {internal/command => command}/state_rm.go | 12 +- .../command => command}/state_rm_test.go | 4 +- {internal/command => command}/state_show.go | 10 +- .../command => command}/state_show_test.go | 8 +- {internal/command => command}/state_test.go | 2 +- {internal/command => command}/taint.go | 14 +- {internal/command => command}/taint_test.go | 4 +- {internal/command => command}/test.go | 30 +- {internal/command => command}/test_test.go | 4 +- .../testdata/apply-config-invalid/main.tf | 0 .../testdata/apply-destroy-targeted/main.tf | 0 .../testdata/apply-error/main.tf | 0 .../testdata/apply-input-partial/main.tf | 0 .../testdata/apply-input/main.tf | 0 .../testdata/apply-plan-no-module/main.tf | 0 .../testdata/apply-replace/main.tf | 0 .../testdata/apply-sensitive-output/main.tf | 0 .../testdata/apply-shutdown/main.tf | 0 .../testdata/apply-targeted/main.tf | 0 .../testdata/apply-terraform-env/main.tf | 0 .../testdata/apply-vars/main.tf | 0 .../testdata/apply/main.tf | 0 .../testdata/apply/output.jsonlog | 0 .../.terraform/terraform.tfstate | 0 .../local-state.tfstate | 0 .../main.tf | 0 .../.terraform/terraform.tfstate | 0 .../local-state.tfstate | 0 .../backend-change-multi-to-multi/main.tf | 0 .../env2/terraform.tfstate | 0 .../.terraform/terraform.tfstate | 0 .../local-state.tfstate | 0 .../main.tf | 0 .../env2/terraform.tfstate | 0 .../.terraform/terraform.tfstate | 0 .../main.tf | 0 .../env2/terraform.tfstate | 0 .../.terraform/environment | 0 .../.terraform/terraform.tfstate | 0 .../backend-change-multi-to-single/main.tf | 0 .../env1/terraform.tfstate | 0 .../env2/terraform.tfstate | 0 .../.terraform/terraform.tfstate | 0 .../local-state.tfstate | 0 .../backend-change-single-to-single/main.tf | 0 .../.terraform/terraform.tfstate | 0 .../backend-change/local-state.tfstate | 0 .../testdata/backend-change/main.tf | 0 .../.terraform/terraform.tfstate | 0 .../local-state-old.tfstate | 0 .../local-state.tfstate | 0 .../backend-changed-with-legacy/main.tf | 0 .../backend-from-state/terraform.tfstate | 0 .../testdata/backend-inmem-locked/main.tf | 0 .../testdata/backend-new-interp/main.tf | 0 .../.terraform/terraform.tfstate | 0 .../local-state-old.tfstate | 0 .../testdata/backend-new-legacy/main.tf | 0 .../local-state.tfstate | 0 .../backend-new-migrate-existing/main.tf | 0 .../terraform.tfstate | 0 .../testdata/backend-new-migrate/main.tf | 0 .../backend-new-migrate/terraform.tfstate | 0 .../testdata/backend-new/main.tf | 0 .../.terraform/terraform.tfstate | 0 .../local-state.tfstate | 0 .../backend-plan-backend-empty-config/main.tf | 0 .../backend-plan-backend-empty/readme.txt | 0 .../local-state.tfstate | 0 .../backend-plan-backend-match/readme.txt | 0 .../local-state.tfstate | 0 .../local-state.tfstate | 0 .../testdata/backend-plan-legacy-data/main.tf | 0 .../backend-plan-legacy-data/state.tfstate | 0 .../testdata/backend-plan-legacy/readme.txt | 0 .../testdata/backend-plan-local-match/main.tf | 0 .../terraform.tfstate | 0 .../main.tf | 0 .../terraform.tfstate | 0 .../testdata/backend-plan-local-newer/main.tf | 0 .../terraform.tfstate | 0 .../testdata/backend-plan-local/main.tf | 0 .../.terraform/terraform.tfstate | 0 .../local-state-old.tfstate | 0 .../local-state.tfstate | 0 .../backend-unchanged-with-legacy/main.tf | 0 .../.terraform/terraform.tfstate | 0 .../backend-unchanged/local-state.tfstate | 0 .../testdata/backend-unchanged/main.tf | 0 .../.terraform/terraform.tfstate | 0 .../local-state-old.tfstate | 0 .../local-state.tfstate | 0 .../backend-unset-with-legacy/main.tf | 0 .../.terraform/terraform.tfstate | 0 .../backend-unset/local-state.tfstate | 0 .../testdata/backend-unset/main.tf | 0 .../command-check-required-version/main.tf | 0 .../command => command}/testdata/empty-file | 0 .../command => command}/testdata/empty/README | 0 .../testdata/fmt/general_in.tf | 0 .../testdata/fmt/general_out.tf | 0 .../testdata/fmt/variable_type_in.tf | 0 .../testdata/fmt/variable_type_out.tf | 0 .../testdata/get/foo/main.tf | 0 .../command => command}/testdata/get/main.tf | 0 .../testdata/graph/main.tf | 0 .../import-missing-resource-config/main.tf | 0 .../child/main.tf | 0 .../import-module-input-variable/main.tf | 0 .../terraform.tfvars | 0 .../import-module-var-file/child/main.tf | 0 .../testdata/import-module-var-file/main.tf | 0 .../import-module-var-file/terraform.tfvars | 0 .../testdata/import-provider-aliased/main.tf | 0 .../import-provider-datasource/main.tf | 0 .../testdata/import-provider-implicit/main.tf | 0 .../testdata/import-provider-invalid/main.tf | 0 .../import-provider-remote-state/main.tf | 0 .../import-provider-var-default/main.tf | 0 .../terraform.tfvars | 0 .../import-provider-var-file/blah.tfvars | 0 .../testdata/import-provider-var-file/main.tf | 0 .../testdata/import-provider-var/main.tf | 0 .../testdata/import-provider/main.tf | 0 .../.terraform/terraform.tfstate | 0 .../input.config | 0 .../local-state.tfstate | 0 .../main.tf | 0 .../.terraform/terraform.tfstate | 0 .../input.config | 0 .../init-backend-config-file-change/main.tf | 0 .../init-backend-config-file/backend.config | 0 .../init-backend-config-file/input.config | 0 .../init-backend-config-file/invalid.config | 0 .../testdata/init-backend-config-file/main.tf | 0 .../testdata/init-backend-config-kv/main.tf | 0 .../testdata/init-backend-empty/main.tf | 0 .../testdata/init-backend-http/main.tf | 0 .../.terraform/terraform.tfstate | 0 .../input.config | 0 .../init-backend-migrate-while-locked/main.tf | 0 .../.terraform/environment | 0 .../.terraform/terraform.tfstate | 0 .../main.tf | 0 .../terraform.tfstate | 0 .../terraform.tfstate.d/foo/terraform.tfstate | 0 .../.terraform/environment | 0 .../.terraform/terraform.tfstate | 0 .../main.tf | 0 .../testdata/init-backend/main.tf | 0 .../main.tf | 0 .../mod/main.tf | 0 .../init-check-required-version-first/main.tf | 0 .../init-check-required-version/main.tf | 0 .../init-cloud-simple/init-cloud-simple.tf | 0 .../terraform-random-bar-1.0.0/main.tf | 0 .../.terraform/modules/modules.json | 0 .../child/main.tf | 0 .../init-get-provider-detected-legacy/main.tf | 0 .../init-get-provider-invalid-package/main.tf | 0 .../main.tf | 0 .../terraform.tfstate | 0 .../testdata/init-get-provider-source/main.tf | 0 .../testdata/init-get-providers/main.tf | 0 .../testdata/init-get/foo/main.tf | 0 .../testdata/init-get/main.tf | 0 .../testdata/init-internal-invalid/main.tf | 0 .../testdata/init-internal/main.tf | 0 .../test/b/1.1.0/os_arch/terraform-provider-b | 0 .../c/2.0.0/os_arch/terraform-provider-c | 0 .../init-legacy-provider-cache/versions.tf | 0 .../testdata/init-legacy-rc/main.tf | 0 .../main.tf | 0 .../testdata/init-provider-lock-file/main.tf | 0 .../testdata/init-provider-now-unused/main.tf | 0 .../testdata/init-providers-lock/main.tf | 0 .../testdata/init-registry-module/main.tf | 0 .../testdata/init-required-providers/main.tf | 0 .../main.tf | 0 .../init-syntax-invalid-no-backend/main.tf | 0 .../init-syntax-invalid-with-backend/main.tf | 0 .../testdata/init/hello.tf | 0 .../testdata/inmem-backend/main.tf | 0 .../testdata/login-oauth-server/main.go | 4 +- .../login-oauth-server/oauthserver.go | 0 .../testdata/login-tfe-server/tfeserver.go | 0 .../modules/.terraform/modules/modules.json | 0 .../testdata/modules/child/main.tf | 0 .../testdata/modules/main.tf | 0 .../testdata/modules/terraform.tfstate | 0 .../testdata/parallelism/main.tf | 0 .../testdata/plan-emptydiff/main.tf | 0 .../testdata/plan-fail-condition/main.tf | 0 .../testdata/plan-invalid/main.tf | 0 .../testdata/plan-out-backend-legacy/main.tf | 0 .../testdata/plan-out-backend/main.tf | 0 .../testdata/plan-provider-input/main.tf | 0 .../testdata/plan-replace/main.tf | 0 .../testdata/plan-vars/main.tf | 0 .../command => command}/testdata/plan/main.tf | 0 .../testdata/plan/output.jsonlog | 0 .../providers-lock/append/.terraform.lock.hcl | 0 .../1.0.0/os_arch/terraform-provider-test | 0 .../testdata/providers-lock/append/main.tf | 0 .../1.0.0/os_arch/terraform-provider-test | 0 .../testdata/providers-lock/basic/main.tf | 0 .../providers-schema/basic/output.json | 0 .../providers-schema/basic/provider.tf | 0 .../testdata/providers-schema/empty/main.tf | 0 .../providers-schema/empty/output.json | 0 .../providers-schema/required/output.json | 0 .../providers-schema/required/provider.tf | 0 .../testdata/providers/basic/main.tf | 0 .../testdata/providers/modules/child/main.tf | 0 .../testdata/providers/modules/main.tf | 0 .../testdata/providers/state/main.tf | 0 .../providers/state/terraform.tfstate | 0 .../testdata/push-backend-new/main.tf | 0 .../testdata/push-input-partial/main.tf | 0 .../testdata/push-input/main.tf | 0 .../testdata/push-no-remote/main.tf | 0 .../testdata/push-no-upload/child/main.tf | 0 .../testdata/push-no-upload/main.tf | 0 .../testdata/push-tfvars/main.tf | 0 .../testdata/push-tfvars/terraform.tfvars | 0 .../command => command}/testdata/push/main.tf | 0 .../testdata/refresh-empty/main.tf | 0 .../testdata/refresh-output/main.tf | 0 .../testdata/refresh-targeted/main.tf | 0 .../testdata/refresh-unset-var/main.tf | 0 .../testdata/refresh-var/main.tf | 0 .../testdata/refresh/main.tf | 0 .../show-corrupt-statefile/terraform.tfstate | 0 .../testdata/show-json-sensitive/main.tf | 0 .../testdata/show-json-sensitive/output.json | 0 .../show-json-state/basic/output.json | 0 .../show-json-state/basic/terraform.tfstate | 0 .../show-json-state/empty/output.json | 0 .../show-json-state/empty/terraform.tfstate | 0 .../show-json-state/modules/bar/main.tf | 0 .../show-json-state/modules/foo/main.tf | 0 .../testdata/show-json-state/modules/main.tf | 0 .../show-json-state/modules/output.json | 0 .../show-json-state/modules/terraform.tfstate | 0 .../show-json-state/no-state/output.json | 0 .../sensitive-variables/output.json | 0 .../sensitive-variables/terraform.tfstate | 0 .../testdata/show-json/basic-create/main.tf | 0 .../show-json/basic-create/output.json | 0 .../testdata/show-json/basic-delete/main.tf | 0 .../show-json/basic-delete/output.json | 0 .../show-json/basic-delete/terraform.tfstate | 0 .../testdata/show-json/basic-update/main.tf | 0 .../show-json/basic-update/output.json | 0 .../show-json/basic-update/terraform.tfstate | 0 .../show-json/conditions/for-refresh.tfstate | 0 .../testdata/show-json/conditions/main.tf | 0 .../conditions/output-refresh-only.json | 0 .../testdata/show-json/conditions/output.json | 0 .../testdata/show-json/drift/main.tf | 0 .../testdata/show-json/drift/output.json | 0 .../show-json/drift/terraform.tfstate | 0 .../show-json/module-depends-on/foo/main.tf | 0 .../show-json/module-depends-on/main.tf | 0 .../show-json/module-depends-on/output.json | 0 .../testdata/show-json/modules/bar/main.tf | 0 .../testdata/show-json/modules/foo/main.tf | 0 .../testdata/show-json/modules/main.tf | 0 .../testdata/show-json/modules/output.json | 0 .../testdata/show-json/moved-drift/main.tf | 0 .../show-json/moved-drift/output.json | 0 .../show-json/moved-drift/terraform.tfstate | 0 .../testdata/show-json/moved/main.tf | 0 .../testdata/show-json/moved/output.json | 0 .../show-json/moved/terraform.tfstate | 0 .../show-json/multi-resource-update/main.tf | 0 .../multi-resource-update/output.json | 0 .../multi-resource-update/terraform.tfstate | 0 .../show-json/nested-module-error/main.tf | 0 .../nested-module-error/modules/main.tf | 0 .../modules/more-modules/main.tf | 0 .../testdata/show-json/nested-modules/main.tf | 0 .../show-json/nested-modules/modules/main.tf | 0 .../modules/more-modules/main.tf | 0 .../show-json/nested-modules/output.json | 0 .../provider-aliasing-conflict/child/main.tf | 0 .../provider-aliasing-conflict/main.tf | 0 .../provider-aliasing-conflict/output.json | 0 .../provider-aliasing-default/child/main.tf | 0 .../child/nested-no-requirements/main.tf | 0 .../child/nested/main.tf | 0 .../provider-aliasing-default/main.tf | 0 .../provider-aliasing-default/output.json | 0 .../show-json/provider-aliasing/child/main.tf | 0 .../provider-aliasing/child/nested/main.tf | 0 .../show-json/provider-aliasing/main.tf | 0 .../show-json/provider-aliasing/output.json | 0 .../provider-version-no-config/main.tf | 0 .../provider-version-no-config/output.json | 0 .../show-json/provider-version/main.tf | 0 .../show-json/provider-version/output.json | 0 .../show-json/requires-replace/main.tf | 0 .../show-json/requires-replace/output.json | 0 .../requires-replace/terraform.tfstate | 0 .../show-json/sensitive-values/main.tf | 0 .../show-json/sensitive-values/output.json | 0 .../testdata/show-json/unknown-output/main.tf | 0 .../show-json/unknown-output/output.json | 0 .../command => command}/testdata/show/main.tf | 0 .../.terraform/terraform.tfstate | 0 .../local-state.tfstate | 0 .../state-list-backend-custom/main.tf | 0 .../.terraform/terraform.tfstate | 0 .../state-list-backend-default/main.tf | 0 .../terraform.tfstate | 0 .../terraform.tfstate | 0 .../.terraform/terraform.tfstate | 0 .../state-pull-backend/local-state.tfstate | 0 .../testdata/state-pull-backend/main.tf | 0 .../.terraform/terraform.tfstate | 0 .../local-state.tfstate | 0 .../testdata/state-push-bad-lineage/main.tf | 0 .../state-push-bad-lineage/replace.tfstate | 0 .../.terraform/terraform.tfstate | 0 .../testdata/state-push-good/main.tf | 0 .../testdata/state-push-good/replace.tfstate | 0 .../.terraform/terraform.tfstate | 0 .../local-state.tfstate | 0 .../testdata/state-push-replace-match/main.tf | 0 .../state-push-replace-match/replace.tfstate | 0 .../.terraform/terraform.tfstate | 0 .../local-state.tfstate | 0 .../testdata/state-push-serial-newer/main.tf | 0 .../state-push-serial-newer/replace.tfstate | 0 .../.terraform/terraform.tfstate | 0 .../local-state.tfstate | 0 .../testdata/state-push-serial-older/main.tf | 0 .../state-push-serial-older/replace.tfstate | 0 .../testdata/statelocker.go | 4 +- .../testdata/test-fails/test-fails.tf | 0 .../testdata/test-fails/tests/hello/hello.tf | 0 .../testdata/test-passes/test-passes.tf | 0 .../testdata/test-passes/tests/hello/hello.tf | 0 .../incorrectmodulename/main.tf | 0 .../incorrectmodulename/output.json | 0 .../validate-invalid/interpolation/main.tf | 0 .../interpolation/output.json | 0 .../testdata/validate-invalid/main.tf | 0 .../missing_defined_var/main.tf | 0 .../missing_defined_var/output.json | 0 .../validate-invalid/missing_quote/main.tf | 0 .../missing_quote/output.json | 0 .../validate-invalid/missing_var/main.tf | 0 .../validate-invalid/missing_var/output.json | 0 .../validate-invalid/multiple_modules/main.tf | 0 .../multiple_modules/output.json | 0 .../multiple_providers/main.tf | 0 .../multiple_providers/output.json | 0 .../multiple_resources/main.tf | 0 .../multiple_resources/output.json | 0 .../testdata/validate-invalid/output.json | 0 .../testdata/validate-invalid/outputs/main.tf | 0 .../validate-invalid/outputs/output.json | 0 .../testdata/validate-valid/main.tf | 0 .../testdata/validate-valid/output.json | 0 .../validate-valid/with-tfvars-file/main.tf | 0 .../with-tfvars-file/terraform.tfvars | 0 .../testdata/variables/main.tf | 0 {internal/command => command}/ui_input.go | 2 +- .../command => command}/ui_input_test.go | 2 +- {internal/command => command}/unlock.go | 6 +- {internal/command => command}/unlock_test.go | 4 +- {internal/command => command}/untaint.go | 14 +- {internal/command => command}/untaint_test.go | 4 +- {internal/command => command}/validate.go | 8 +- .../command => command}/validate_test.go | 6 +- {internal/command => command}/version.go | 6 +- {internal/command => command}/version_test.go | 6 +- {internal/command => command}/views/apply.go | 12 +- .../command => command}/views/apply_test.go | 8 +- .../command => command}/views/hook_count.go | 8 +- .../views/hook_count_test.go | 10 +- .../command => command}/views/hook_json.go | 12 +- .../views/hook_json_test.go | 10 +- .../command => command}/views/hook_ui.go | 12 +- .../command => command}/views/hook_ui_test.go | 14 +- .../command => command}/views/json/change.go | 2 +- .../views/json/change_summary.go | 0 .../views/json/diagnostic.go | 4 +- .../views/json/diagnostic_test.go | 4 +- .../views/json/function.go | 0 .../views/json/function_test.go | 0 .../command => command}/views/json/hook.go | 4 +- .../views/json/message_types.go | 0 .../command => command}/views/json/output.go | 6 +- .../views/json/output_test.go | 8 +- .../views/json/resource_addr.go | 2 +- ...error-whose-range-starts-at-a-newline.json | 0 ...highlight-range-at-end-of-source-code.json | 0 .../error-with-multi-line-snippet.json | 0 ...llection-containing-a-sensitive-value.json | 0 ...e-when-not-caused-by-sensitive-values.json | 0 ...pression-referring-to-sensitive-value.json | 0 ...rce-code-subject-and-known-expression.json | 0 ...ype-when-not-caused-by-unknown-values.json | 0 ...nd-unknown-expression-of-unknown-type.json | 0 ...subject-and-unknown-string-expression.json | 0 ...th-source-code-subject-but-no-context.json | 0 ...bject-with-multiple-expression-values.json | 0 .../error-with-source-code-subject.json | 0 .../error-with-source-code-unavailable.json | 0 ...ror-with-unset-highlight-end-position.json | 0 .../diagnostic/sourceless-warning.json | 0 .../command => command}/views/json_view.go | 4 +- .../views/json_view_test.go | 10 +- .../command => command}/views/operation.go | 22 +- .../views/operation_test.go | 16 +- {internal/command => command}/views/output.go | 8 +- .../command => command}/views/output_test.go | 6 +- {internal/command => command}/views/plan.go | 6 +- .../command => command}/views/plan_test.go | 14 +- .../command => command}/views/refresh.go | 10 +- .../command => command}/views/refresh_test.go | 8 +- {internal/command => command}/views/show.go | 20 +- .../command => command}/views/show_test.go | 18 +- .../command => command}/views/state_locker.go | 2 +- {internal/command => command}/views/test.go | 10 +- .../command => command}/views/test_test.go | 6 +- .../views/testdata/show/main.tf | 0 .../command => command}/views/validate.go | 8 +- .../views/validate_test.go | 6 +- {internal/command => command}/views/view.go | 8 +- .../command => command}/webbrowser/mock.go | 2 +- .../webbrowser/mock_test.go | 0 .../command => command}/webbrowser/native.go | 0 .../webbrowser/webbrowser.go | 0 {internal/command => command}/workdir/dir.go | 0 {internal/command => command}/workdir/doc.go | 0 .../workdir/normalize_path.go | 0 .../workdir/plugin_dirs.go | 0 .../workdir/plugin_dirs_test.go | 0 .../command => command}/workspace_command.go | 0 .../workspace_command_test.go | 14 +- .../command => command}/workspace_delete.go | 10 +- .../command => command}/workspace_list.go | 2 +- .../command => command}/workspace_new.go | 10 +- .../command => command}/workspace_select.go | 2 +- .../command => command}/workspace_show.go | 0 commands.go | 16 +- .../communicator.go | 10 +- .../communicator_mock.go | 4 +- .../communicator_test.go | 0 .../remote/command.go | 0 .../remote/command_test.go | 0 .../shared/shared.go | 2 +- .../shared/shared_test.go | 0 .../ssh/communicator.go | 6 +- .../ssh/communicator_test.go | 2 +- .../ssh/http_proxy.go | 0 .../ssh/password.go | 0 .../ssh/password_test.go | 0 .../ssh/provisioner.go | 2 +- .../ssh/provisioner_test.go | 0 .../ssh/ssh_test.go | 0 .../winrm/communicator.go | 4 +- .../winrm/communicator_test.go | 4 +- .../winrm/provisioner.go | 2 +- .../winrm/provisioner_test.go | 0 {internal/configs => configs}/backend.go | 2 +- {internal/configs => configs}/checks.go | 4 +- {internal/configs => configs}/cloud.go | 0 {internal/configs => configs}/compat_shim.go | 0 {internal/configs => configs}/config.go | 6 +- {internal/configs => configs}/config_build.go | 2 +- .../configs => configs}/config_build_test.go | 0 {internal/configs => configs}/config_test.go | 6 +- .../configload/copy_dir.go | 0 .../configload/copy_dir_test.go | 0 .../configs => configs}/configload/doc.go | 0 .../configs => configs}/configload/inode.go | 0 .../configload/inode_freebsd.go | 0 .../configload/inode_windows.go | 0 .../configs => configs}/configload/loader.go | 4 +- .../configload/loader_load.go | 2 +- .../configload/loader_load_test.go | 2 +- .../configload/loader_snapshot.go | 4 +- .../configload/loader_snapshot_test.go | 0 .../configload/loader_test.go | 0 .../configload/module_mgr.go | 4 +- .../.terraform/modules/child/empty.tf | 0 .../.terraform/modules/modules.json | 0 .../add-version-constraint.tf | 0 .../.terraform/modules/modules.json | 0 .../foo/bar/main.tf | 0 .../already-installed-now-invalid/foo/main.tf | 0 .../already-installed-now-invalid/root.tf | 0 .../.terraform/modules/child_a/child_a.tf | 0 .../modules/child_a/child_c/child_c.tf | 0 .../modules/child_b.child_d/child_d.tf | 0 .../.terraform/modules/child_b/child_b.tf | 0 .../.terraform/modules/modules.json | 0 .../testdata/already-installed/root.tf | 0 .../.terraform/modules/modules.json | 0 .../child-provider-child-count.tf | 0 .../child/child-provider-child-count-child.tf | 0 .../child-provider-child-count-grandchild.tf | 0 .../.terraform/modules/modules.json | 0 .../child-provider-grandchild-count.tf | 0 .../child-provider-grandchild-count-child.tf | 0 ...ld-provider-grandchild-count-grandchild.tf | 0 .../configload/testdata/empty/.gitignore | 0 .../testdata/go-getter-modules/.gitignore | 0 .../testdata/go-getter-modules/root.tf | 0 .../.terraform/modules/modules.json | 0 .../invalid-names-in-submodules/main.tf | 0 .../invalid-names-in-submodules/sub/main.tf | 0 .../configload/testdata/invalid-names/main.tf | 0 .../testdata/local-modules/child_a/child_a.tf | 0 .../local-modules/child_a/child_b/child_b.tf | 0 .../configload/testdata/local-modules/root.tf | 0 .../.terraform/modules/modules.json | 0 .../testdata/module-depends-on/child/main.tf | 0 .../testdata/module-depends-on/child2/main.tf | 0 .../testdata/module-depends-on/root.tf | 0 .../testdata/registry-modules/.gitignore | 0 .../testdata/registry-modules/root.tf | 0 .../configs => configs}/configload/testing.go | 0 .../configschema/coerce_value.go | 0 .../configschema/coerce_value_test.go | 2 +- .../configschema/decoder_spec.go | 0 .../configschema/decoder_spec_test.go | 0 .../configs => configs}/configschema/doc.go | 0 .../configschema/empty_value.go | 0 .../configschema/empty_value_test.go | 0 .../configschema/implied_type.go | 0 .../configschema/implied_type_test.go | 0 .../configschema/internal_validate.go | 0 .../configschema/internal_validate_test.go | 0 .../configs => configs}/configschema/marks.go | 2 +- .../configschema/marks_test.go | 2 +- .../configschema/nestingmode_string.go | 0 .../configschema/none_required.go | 0 .../configs => configs}/configschema/path.go | 0 .../configschema/path_test.go | 0 .../configschema/schema.go | 0 .../configschema/validate_traversal.go | 4 +- .../configschema/validate_traversal_test.go | 0 {internal/configs => configs}/depends_on.go | 0 {internal/configs => configs}/doc.go | 0 .../escaping_blocks_test.go | 0 {internal/configs => configs}/experiments.go | 4 +- .../configs => configs}/experiments_test.go | 2 +- .../configs => configs}/hcl2shim/flatmap.go | 0 .../hcl2shim/flatmap_test.go | 0 .../configs => configs}/hcl2shim/paths.go | 0 .../hcl2shim/paths_test.go | 0 .../hcl2shim/single_attr_body.go | 0 .../configs => configs}/hcl2shim/values.go | 2 +- .../hcl2shim/values_equiv.go | 0 .../hcl2shim/values_equiv_test.go | 0 .../hcl2shim/values_test.go | 2 +- {internal/configs => configs}/module.go | 4 +- {internal/configs => configs}/module_call.go | 4 +- .../configs => configs}/module_call_test.go | 2 +- {internal/configs => configs}/module_merge.go | 2 +- .../configs => configs}/module_merge_body.go | 0 .../configs => configs}/module_merge_test.go | 2 +- {internal/configs => configs}/module_test.go | 2 +- {internal/configs => configs}/moved.go | 2 +- {internal/configs => configs}/moved_test.go | 2 +- {internal/configs => configs}/named_values.go | 2 +- {internal/configs => configs}/parser.go | 0 .../configs => configs}/parser_config.go | 0 .../configs => configs}/parser_config_dir.go | 0 .../parser_config_dir_test.go | 0 .../configs => configs}/parser_config_test.go | 0 {internal/configs => configs}/parser_test.go | 0 .../configs => configs}/parser_values.go | 0 .../configs => configs}/parser_values_test.go | 0 {internal/configs => configs}/provider.go | 4 +- .../configs => configs}/provider_meta.go | 0 .../provider_requirements.go | 2 +- .../provider_requirements_test.go | 2 +- .../configs => configs}/provider_test.go | 2 +- .../provider_validation.go | 2 +- {internal/configs => configs}/provisioner.go | 0 .../provisioneronfailure_string.go | 0 .../provisionerwhen_string.go | 0 {internal/configs => configs}/resource.go | 6 +- {internal/configs => configs}/synth_body.go | 0 .../configs => configs}/synth_body_test.go | 0 .../testdata/config-build/child_a/child_a.tf | 0 .../testdata/config-build/child_b/child_b.tf | 0 .../testdata/config-build/child_c/child_c.tf | 0 .../testdata/config-build/root.tf | 0 .../config-diagnostics/empty-configs/main.tf | 0 .../empty-configs/mod/main.tf | 0 .../config-diagnostics/empty-configs/warnings | 0 .../config-diagnostics/incorrect-type/errors | 0 .../config-diagnostics/incorrect-type/main.tf | 0 .../incorrect-type/mod/main.tf | 0 .../incorrect-type/warnings | 0 .../invalid-provider/errors | 0 .../invalid-provider/main.tf | 0 .../invalid-provider/mod/main.tf | 0 .../nested-provider/child/child2/main.tf | 0 .../nested-provider/child/main.tf | 0 .../config-diagnostics/nested-provider/errors | 0 .../nested-provider/root.tf | 0 .../override-provider/errors | 0 .../override-provider/main.tf | 0 .../override-provider/mod/main.tf | 0 .../pass-inherited-provider/main.tf | 0 .../pass-inherited-provider/mod/main.tf | 0 .../pass-inherited-provider/mod2/main.tf | 0 .../pass-inherited-provider/warnings | 0 .../config-diagnostics/required-alias/errors | 0 .../config-diagnostics/required-alias/main.tf | 0 .../required-alias/mod/main.tf | 0 .../unexpected-provider/main.tf | 0 .../unexpected-provider/mod/main.tf | 0 .../unexpected-provider/warnings | 0 .../unknown-root-provider/main.tf | 0 .../unknown-root-provider/mod/main.tf | 0 .../unknown-root-provider/warnings | 0 .../with-depends-on/main.tf | 0 .../with-depends-on/mod1/main.tf | 0 .../with-depends-on/mod1/mod2/main.tf | 0 .../with-depends-on/mod1/mod2/mod3/main.tf | 0 .../testdata/dir-empty/.gitkeep | 0 .../testdata/duplicate-local-name/main.tf | 0 .../error-files/destroy-provisioners.tf | 0 .../testdata/error-files/ignore_changes.tf | 0 .../error-files/invalid_language_edition.tf | 0 ...ule-invalid-registry-source-with-module.tf | 0 .../module-local-source-with-version.tf | 0 .../precondition-postcondition-constant.tf | 0 .../precondition-postcondition-selfref.tf | 0 .../error-files/provider-source-prefix.tf | 0 .../required-providers-toplevel.tf | 0 .../unsupported_language_edition.tf | 0 .../error-files/variable_type_quoted.tf | 0 .../error-files/vendor_provisioners.tf | 0 .../data/data-escaping-block.tf | 0 .../escaping-blocks/module/child/nothing.tf | 0 .../module/module-escaping-block.tf | 0 .../provider/provider-escaping-block.tf | 0 .../resource/resource-escaping-block.tf | 0 .../concluded/concluded_experiment.tf | 0 .../experiments/current/current_experiment.tf | 0 .../invalid/invalid_experiments.tf | 0 .../experiments/unknown/unknown_experiment.tf | 0 .../invalid-files/data-count-and-for_each.tf | 0 .../data-invalid-provider-reference.tf | 0 .../invalid-files/data-reserved-locals.tf | 0 .../invalid-files/data-resource-lifecycle.tf | 0 .../invalid-files/everything-is-a-plan.tf | 0 .../invalid-files/interp-in-data-label.tf | 0 .../invalid-files/interp-in-rsrc-label.tf | 0 .../invalid-files/json-as-native-syntax.tf | 0 .../testdata/invalid-files/module-calls.tf | 0 .../native-syntax-as-json.tf.json | 0 .../precondition-postcondition-badref.tf | 0 ...ndition-postcondition-missing-condition.tf | 0 .../provider-localname-normalization.tf | 0 .../invalid-files/provider-reserved.tf | 0 .../testdata/invalid-files/provider-syntax.tf | 0 .../resource-count-and-for_each.tf | 0 .../resource-invalid-provider-reference.tf | 0 .../resource-lifecycle-badbool.tf | 0 .../invalid-files/resource-name-invalid.tf | 0 .../invalid-files/resource-reserved-locals.tf | 0 .../resources-ignorechanges-all-legacymix.tf | 0 .../invalid-files/triggered-invalid-each.tf | 0 .../triggered-invalid-expression.tf | 0 .../testdata/invalid-files/unexpected-attr.tf | 0 .../invalid-files/unexpected-block.tf | 0 .../invalid-files/variable-bad-default.tf | 0 .../invalid-files/variable-bad-sensitive.tf | 0 .../invalid-files/variable-type-unknown.tf | 0 .../variable-validation-condition-badref.tf | 0 .../variable-validation-condition-noref.tf | 0 .../invalid-files/version-variable.tf | 0 .../testdata/invalid-files/zerolen.tf.json | 0 .../multiple-required-providers/a.tf | 0 .../multiple-required-providers/b.tf | 0 .../nullable-with-default-null/main.tf | 0 .../override-cloud-duplicates/main.tf | 0 .../override-cloud-duplicates/override.tf | 0 .../override-nonexist-variable/override.tf | 0 .../base.tf | 0 .../override.tf | 0 .../provider-meta/invalid-interpolation.tf | 0 .../nested-backend-warning/child/child.tf | 0 .../testdata/nested-backend-warning/root.tf | 0 .../nested-cloud-warning/child/child.tf | 0 .../testdata/nested-cloud-warning/root.tf | 0 .../testdata/nested-errors/child_a/child_a.tf | 0 .../testdata/nested-errors/child_c/child_c.tf | 0 .../testdata/nested-errors/root.tf | 0 .../grandchild/provider-reqs-grandchild.tf | 0 .../child/provider-reqs-child.tf | 0 .../provider-reqs/provider-reqs-root.tf | 0 .../testdata/providers-explicit-fqn/root.tf | 0 .../testdata/valid-files/backend.tf | 0 .../testdata/valid-files/cloud.tf | 0 .../testdata/valid-files/data-sources.tf | 0 .../testdata/valid-files/empty.tf | 0 .../testdata/valid-files/empty.tf.json | 0 .../testdata/valid-files/locals.tf | 0 .../testdata/valid-files/locals.tf.json | 0 .../valid-files/object-optional-attrs.tf | 0 .../testdata/valid-files/outputs.tf | 0 .../preconditions-postconditions.tf | 0 .../testdata/valid-files/provider-configs.tf | 0 .../valid-files/providers-explicit-implied.tf | 0 .../testdata/valid-files/references.tf.json | 0 .../valid-files/required-providers.tf | 0 .../testdata/valid-files/required-version.tf | 0 .../resources-ignorechanges-all.tf | 0 .../resources-ignorechanges-all.tf.json | 0 .../testdata/valid-files/resources.tf | 0 .../testdata/valid-files/resources.tf.json | 0 .../valid-files/valid-language-edition.tf | 0 .../valid-files/variable_validation.tf | 0 .../testdata/valid-files/variables.tf | 0 .../testdata/valid-files/variables.tf.json | 0 .../testdata/valid-modules/empty/README | 0 .../implied-providers/providers.tf | 0 .../implied-providers/resources.tf | 0 .../moved-blocks/moved-blocks-1.tf | 0 .../moved-blocks/moved-blocks-2.tf | 0 .../nested-providers-fqns/child/main.tf | 0 .../nested-providers-fqns/main.tf | 0 .../override-backend-no-base/main.tf | 0 .../override-backend-no-base/override.tf | 0 .../override-backend-with-cloud/main.tf | 0 .../override-backend-with-cloud/override.tf | 0 .../valid-modules/override-backend/main.tf | 0 .../override-backend/override.tf | 0 .../override-cloud-no-base/main.tf | 0 .../override-cloud-no-base/override.tf | 0 .../valid-modules/override-cloud/main.tf | 0 .../valid-modules/override-cloud/override.tf | 0 .../override-dynamic-block-base/a_override.tf | 0 .../override-dynamic-block-base/base.tf | 0 .../a_override.tf | 0 .../override-dynamic-block-override/base.tf | 0 .../override-ignore-changes/main.tf | 0 .../override-ignore-changes/main_override.tf | 0 .../override-module/a_override.tf | 0 .../override-module/b_override.tf | 0 .../valid-modules/override-module/primary.tf | 0 .../override-output-sensitive/override.tf | 0 .../override-output-sensitive/primary.tf | 0 .../override-resource-provider/a_override.tf | 0 .../override-resource-provider/base.tf | 0 .../override-variable-sensitive/a_override.tf | 0 .../override-variable-sensitive/b_override.tf | 0 .../override-variable-sensitive/primary.tf | 0 .../override-variable/a_override.tf | 0 .../override-variable/b_override.tf | 0 .../override-variable/primary.tf | 0 .../valid-modules/provider-aliases/main.tf | 0 .../valid-modules/provider-meta/main.tf | 0 .../valid-modules/providers-fqns/main.tf | 0 .../required-providers-after-resource/main.tf | 0 .../providers.tf | 0 .../bar_provider_override.tf | 0 .../required-providers-overrides/main.tf | 0 .../required-providers-overrides/providers.tf | 0 .../testdata/warning-files/depends_on.tf | 0 .../testdata/warning-files/provider_ref.tf | 0 .../warning-files/provisioner_keyword.tf | 0 {internal/configs => configs}/util.go | 0 .../configs => configs}/variable_type_hint.go | 0 .../variabletypehint_string.go | 0 .../configs => configs}/version_constraint.go | 0 {internal/copy => copy}/copy_dir.go | 0 {internal/copy => copy}/copy_dir_test.go | 0 {internal/copy => copy}/copy_file.go | 0 {internal/dag => dag}/dag.go | 2 +- {internal/dag => dag}/dag_test.go | 4 +- {internal/dag => dag}/dot.go | 0 {internal/dag => dag}/dot_test.go | 0 {internal/dag => dag}/edge.go | 0 {internal/dag => dag}/edge_test.go | 0 {internal/dag => dag}/graph.go | 0 {internal/dag => dag}/graph_test.go | 0 {internal/dag => dag}/marshal.go | 0 {internal/dag => dag}/marshal_test.go | 0 {internal/dag => dag}/set.go | 0 {internal/dag => dag}/set_test.go | 0 {internal/dag => dag}/tarjan.go | 0 {internal/dag => dag}/tarjan_test.go | 0 {internal/dag => dag}/walk.go | 2 +- {internal/dag => dag}/walk_test.go | 2 +- {internal/depsfile => depsfile}/doc.go | 0 {internal/depsfile => depsfile}/locks.go | 4 +- {internal/depsfile => depsfile}/locks_file.go | 8 +- .../depsfile => depsfile}/locks_file_test.go | 6 +- {internal/depsfile => depsfile}/locks_test.go | 4 +- {internal/depsfile => depsfile}/paths.go | 0 .../testdata/locks-files/empty.hcl | 0 .../locks-files/invalid-provider-addrs.hcl | 0 .../testdata/locks-files/invalid-versions.hcl | 0 .../locks-files/unsupported-block.hcl | 0 .../locks-files/valid-provider-locks.hcl | 0 {internal/depsfile => depsfile}/testing.go | 0 .../name_suggestion.go | 0 .../name_suggestion_test.go | 0 {internal/e2e => e2e}/e2e.go | 8 +- .../earlyconfig => earlyconfig}/config.go | 10 +- .../config_build.go | 4 +- .../config_test.go | 6 +- .../diagnostics.go | 2 +- {internal/earlyconfig => earlyconfig}/doc.go | 0 .../earlyconfig => earlyconfig}/module.go | 2 +- .../child/provider-reqs-child.tf | 0 .../provider-reqs/provider-reqs-root.tf | 0 {internal/experiments => experiments}/doc.go | 0 .../experiments => experiments}/errors.go | 0 .../experiments => experiments}/experiment.go | 0 {internal/experiments => experiments}/set.go | 0 .../experiments => experiments}/testing.go | 0 {internal/getmodules => getmodules}/doc.go | 0 .../file_detector.go | 0 {internal/getmodules => getmodules}/getter.go | 2 +- .../getmodules => getmodules}/installer.go | 0 .../getmodules => getmodules}/package.go | 0 {internal/getmodules => getmodules}/subdir.go | 0 .../didyoumean.go | 2 +- .../didyoumean_test.go | 2 +- .../getproviders => getproviders}/doc.go | 0 .../getproviders => getproviders}/errors.go | 2 +- .../filesystem_mirror_source.go | 2 +- .../filesystem_mirror_source_test.go | 2 +- .../filesystem_search.go | 2 +- .../filesystem_search_test.go | 2 +- .../hanging_source.go | 2 +- .../getproviders => getproviders}/hash.go | 0 .../hash_test.go | 0 .../http_mirror_source.go | 6 +- .../http_mirror_source_test.go | 2 +- .../memoize_source.go | 2 +- .../memoize_source_test.go | 2 +- .../mock_source.go | 2 +- .../multi_source.go | 2 +- .../multi_source_test.go | 2 +- .../package_authentication.go | 0 .../package_authentication_test.go | 0 .../public_keys.go | 0 .../registry_client.go | 6 +- .../registry_client_test.go | 2 +- .../registry_source.go | 2 +- .../registry_source_test.go | 2 +- .../getproviders => getproviders}/source.go | 2 +- .../darwin_amd64/terraform-provider-null | 0 .../2.0.0/linux_amd64/terraform-provider-null | 0 .../hashicorp/null/invalid | 0 ...raform-provider-null_2.1.0_linux_amd64.zip | 0 .../null/terraform-provider-null_invalid.zip | 0 ...-provider-null_invalid_invalid_invalid.zip | 0 .../terraform-provider-random-beta | 0 .../linux_amd64/terraform-provider-random | 0 .../linux_amd64/terraform-provider-legacy | 0 .../darwin_amd64/terraform-provider-null | 0 .../2.0.0/linux_amd64/terraform-provider-null | 0 .../hashicorp/null/invalid | 0 ...raform-provider-null_2.1.0_linux_amd64.zip | 0 .../null/terraform-provider-null_invalid.zip | 0 ...-provider-null_invalid_invalid_invalid.zip | 0 .../terraform-provider-random-beta | 0 .../linux_amd64/terraform-provider-random | 0 .../0.1.0-alpha.2/darwin_amd64/extra-data.txt | 0 .../terraform-provider-happycloud | 0 .../1.0.0/linux_amd64/terraform-provider-bar | 0 .../symlinks/real/example.net | 0 .../search-local-directory/symlinks/symlink | 0 .../getproviders => getproviders}/types.go | 2 +- .../types_test.go | 0 {internal/grpcwrap => grpcwrap}/provider.go | 6 +- {internal/grpcwrap => grpcwrap}/provider6.go | 6 +- .../grpcwrap => grpcwrap}/provisioner.go | 10 +- .../slowmessage/slowmessage.go | 0 .../slowmessage/slowmessage_test.go | 0 {internal/httpclient => httpclient}/client.go | 0 .../httpclient => httpclient}/client_test.go | 0 .../httpclient => httpclient}/useragent.go | 0 .../useragent_test.go | 0 {internal/initwd => initwd}/doc.go | 0 {internal/initwd => initwd}/from_module.go | 12 +- .../initwd => initwd}/from_module_test.go | 10 +- {internal/initwd => initwd}/load_config.go | 6 +- {internal/initwd => initwd}/module_install.go | 16 +- .../initwd => initwd}/module_install_hooks.go | 0 .../initwd => initwd}/module_install_test.go | 16 +- .../testdata/already-installed/root.tf | 0 .../testdata/empty/.gitignore | 0 .../testdata/go-getter-modules/.gitignore | 0 .../testdata/go-getter-modules/root.tf | 0 .../.gitignore | 0 .../invalid-version-constraint-local/root.tf | 0 .../invalid-version-constraint/.gitignore | 0 .../invalid-version-constraint/root.tf | 0 .../child/package-escape-child.tf | 0 .../grandchild/package-escape-grandchild.tf | 0 .../package-escape.tf | 0 .../package-prefix.tf | 0 .../package/child/package-prefix-child.tf | 0 .../grandchild/package-prefix-grandchild.tf | 0 .../local-module-error/child_a/main.tf | 0 .../testdata/local-module-error/main.tf | 0 .../local-module-symlink/child_a/child_a.tf | 0 .../child_a/child_b/child_b.tf | 0 .../local-module-symlink/modules/child_a | 0 .../testdata/local-module-symlink/root.tf | 0 .../testdata/local-modules/child_a/child_a.tf | 0 .../local-modules/child_a/child_b/child_b.tf | 0 .../testdata/local-modules/root.tf | 0 .../root.tf | 0 .../prerelease-version-constraint/root.tf | 0 .../testdata/registry-modules/.gitignore | 0 .../testdata/registry-modules/root.tf | 0 {internal/initwd => initwd}/testing.go | 8 +- {internal/instances => instances}/expander.go | 2 +- .../instances => instances}/expander_test.go | 2 +- .../instances => instances}/expansion_mode.go | 2 +- .../instance_key_data.go | 0 {internal/instances => instances}/set.go | 2 +- {internal/instances => instances}/set_test.go | 2 +- .../windows_amd64/terraform-provider-null.exe | 1 - .../terraform-foo-bar_v1.0.0.exe | 0 internal/plugin/mock_proto/generate.go | 3 - internal/provider-simple-v6/main/main.go | 16 - internal/provider-simple/main/main.go | 16 - .../windows_amd64/terraform-provider-null.exe | 1 - internal/terraform/context.go | 431 - internal/terraform/context_apply.go | 187 - internal/terraform/context_apply2_test.go | 1956 --- internal/terraform/context_apply_test.go | 12632 ---------------- internal/terraform/context_eval.go | 96 - internal/terraform/context_eval_test.go | 130 - internal/terraform/context_fixtures_test.go | 85 - internal/terraform/context_import.go | 92 - internal/terraform/context_import_test.go | 1042 -- internal/terraform/context_input.go | 206 - internal/terraform/context_input_test.go | 469 - internal/terraform/context_plan.go | 867 -- internal/terraform/context_plan2_test.go | 4037 ----- internal/terraform/context_plan_test.go | 6931 --------- internal/terraform/context_plugins.go | 209 - internal/terraform/context_plugins_test.go | 83 - internal/terraform/context_refresh.go | 37 - internal/terraform/context_refresh_test.go | 1685 --- internal/terraform/context_test.go | 1005 -- internal/terraform/context_validate.go | 80 - internal/terraform/context_validate_test.go | 2484 --- internal/terraform/context_walk.go | 144 - internal/terraform/diagnostics.go | 42 - internal/terraform/eval_conditions.go | 238 - internal/terraform/eval_context.go | 204 - internal/terraform/eval_context_builtin.go | 504 - .../terraform/eval_context_builtin_test.go | 88 - internal/terraform/eval_context_mock.go | 401 - internal/terraform/eval_count.go | 107 - internal/terraform/eval_count_test.go | 46 - internal/terraform/eval_for_each.go | 193 - internal/terraform/eval_for_each_test.go | 232 - internal/terraform/eval_provider.go | 59 - internal/terraform/eval_provider_test.go | 55 - internal/terraform/eval_variable.go | 394 - internal/terraform/eval_variable_test.go | 1345 -- internal/terraform/evaluate.go | 966 -- internal/terraform/evaluate_test.go | 566 - internal/terraform/evaluate_triggers.go | 143 - internal/terraform/evaluate_triggers_test.go | 94 - internal/terraform/evaluate_valid.go | 318 - internal/terraform/evaluate_valid_test.go | 121 - internal/terraform/execute.go | 9 - internal/terraform/features.go | 7 - internal/terraform/graph.go | 135 - internal/terraform/graph_builder.go | 65 - internal/terraform/graph_builder_apply.go | 175 - .../terraform/graph_builder_apply_test.go | 751 - internal/terraform/graph_builder_eval.go | 108 - internal/terraform/graph_builder_plan.go | 305 - internal/terraform/graph_builder_plan_test.go | 273 - internal/terraform/graph_builder_test.go | 64 - internal/terraform/graph_dot.go | 9 - internal/terraform/graph_dot_test.go | 313 - .../terraform/graph_interface_subgraph.go | 17 - internal/terraform/graph_test.go | 56 - internal/terraform/graph_walk.go | 25 - internal/terraform/graph_walk_context.go | 137 - internal/terraform/graph_walk_operation.go | 17 - internal/terraform/graph_walk_test.go | 9 - internal/terraform/hook.go | 145 - internal/terraform/hook_mock.go | 274 - internal/terraform/hook_stop.go | 97 - internal/terraform/hook_stop_test.go | 9 - internal/terraform/hook_test.go | 132 - internal/terraform/instance_expanders.go | 7 - internal/terraform/marks.go | 39 - internal/terraform/marks_test.go | 105 - internal/terraform/node_data_destroy.go | 24 - internal/terraform/node_data_destroy_test.go | 48 - internal/terraform/node_local.go | 180 - internal/terraform/node_local_test.go | 85 - internal/terraform/node_module_expand.go | 252 - internal/terraform/node_module_expand_test.go | 128 - internal/terraform/node_module_variable.go | 244 - .../terraform/node_module_variable_test.go | 121 - internal/terraform/node_output.go | 610 - internal/terraform/node_output_test.go | 187 - internal/terraform/node_provider.go | 179 - internal/terraform/node_provider_abstract.go | 95 - internal/terraform/node_provider_eval.go | 19 - internal/terraform/node_provider_test.go | 524 - internal/terraform/node_resource_abstract.go | 518 - .../node_resource_abstract_instance.go | 2400 --- .../node_resource_abstract_instance_test.go | 183 - .../terraform/node_resource_abstract_test.go | 312 - internal/terraform/node_resource_apply.go | 112 - .../terraform/node_resource_apply_instance.go | 486 - .../terraform/node_resource_apply_test.go | 63 - internal/terraform/node_resource_destroy.go | 234 - .../node_resource_destroy_deposed.go | 334 - .../node_resource_destroy_deposed_test.go | 212 - internal/terraform/node_resource_import.go | 251 - internal/terraform/node_resource_plan.go | 402 - .../terraform/node_resource_plan_destroy.go | 122 - .../terraform/node_resource_plan_instance.go | 422 - .../terraform/node_resource_plan_orphan.go | 285 - .../node_resource_plan_orphan_test.go | 210 - internal/terraform/node_resource_validate.go | 592 - .../terraform/node_resource_validate_test.go | 635 - internal/terraform/node_root_variable.go | 115 - internal/terraform/node_root_variable_test.go | 167 - internal/terraform/node_value.go | 10 - internal/terraform/phasestate_string.go | 25 - internal/terraform/provider_mock.go | 539 - internal/terraform/provisioner_mock.go | 104 - internal/terraform/provisioner_mock_test.go | 27 - internal/terraform/reduce_plan.go | 32 - internal/terraform/reduce_plan_test.go | 443 - .../terraform/resource_provider_mock_test.go | 102 - internal/terraform/schemas.go | 187 - internal/terraform/schemas_test.go | 65 - internal/terraform/terraform_test.go | 1083 -- .../terraform/testdata/apply-blank/main.tf | 1 - .../testdata/apply-cancel-block/main.tf | 3 - .../testdata/apply-cancel-provisioner/main.tf | 7 - .../terraform/testdata/apply-cancel/main.tf | 7 - .../testdata/apply-cbd-count/main.tf | 8 - .../testdata/apply-cbd-cycle/main.tf | 19 - .../apply-cbd-depends-non-cbd/main.tf | 12 - .../testdata/apply-cbd-deposed-only/main.tf | 5 - .../terraform/testdata/apply-compute/main.tf | 13 - .../testdata/apply-count-dec-one/main.tf | 3 - .../testdata/apply-count-dec/main.tf | 8 - .../testdata/apply-count-tainted/main.tf | 4 - .../testdata/apply-count-variable-ref/main.tf | 11 - .../testdata/apply-count-variable/main.tf | 8 - .../testdata/apply-data-basic/main.tf | 1 - .../testdata/apply-data-sensitive/main.tf | 8 - .../apply-depends-create-before/main.tf | 10 - .../testdata/apply-destroy-cbd/main.tf | 7 - .../apply-destroy-computed/child/main.tf | 5 - .../testdata/apply-destroy-computed/main.tf | 6 - .../child/main.tf | 5 - .../apply-destroy-cross-providers/main.tf | 7 - .../testdata/apply-destroy-data-cycle/main.tf | 14 - .../apply-destroy-data-resource/main.tf | 3 - .../child/main.tf | 3 - .../child/subchild/main.tf | 5 - .../child/subchild/subsubchild/main.tf | 1 - .../main.tf | 3 - .../testdata/apply-destroy-depends-on/main.tf | 5 - .../child/child2/main.tf | 5 - .../child/main.tf | 8 - .../main.tf | 9 - .../child/main.tf | 5 - .../apply-destroy-mod-var-and-count/main.tf | 4 - .../child/child.tf | 7 - .../main.tf | 4 - .../child/main.tf | 1 - .../main.tf | 3 - .../child/main.tf | 9 - .../apply-destroy-module-with-attrs/main.tf | 10 - .../middle/bottom/bottom.tf | 5 - .../middle/middle.tf | 10 - .../top.tf | 4 - .../apply-destroy-nested-module/child/main.tf | 3 - .../child/subchild/main.tf | 1 - .../apply-destroy-nested-module/main.tf | 5 - .../testdata/apply-destroy-outputs/main.tf | 34 - .../apply-destroy-provisioner/main.tf | 3 - .../testdata/apply-destroy-tainted/main.tf | 17 - .../apply-destroy-targeted-count/main.tf | 7 - .../apply-destroy-with-locals/main.tf | 8 - .../terraform/testdata/apply-destroy/main.tf | 7 - .../testdata/apply-empty-module/child/main.tf | 11 - .../testdata/apply-empty-module/main.tf | 7 - .../apply-error-create-before/main.tf | 6 - .../terraform/testdata/apply-error/main.tf | 7 - .../terraform/testdata/apply-escape/main.tf | 3 - .../apply-good-create-before-update/main.tf | 7 - .../testdata/apply-good-create-before/main.tf | 6 - .../terraform/testdata/apply-good/main.tf | 7 - .../terraform/testdata/apply-idattr/main.tf | 3 - .../testdata/apply-ignore-changes-all/main.tf | 7 - .../apply-ignore-changes-create/main.tf | 7 - .../testdata/apply-ignore-changes-dep/main.tf | 12 - .../apply-inconsistent-with-plan/main.tf | 2 - .../testdata/apply-interpolated-count/main.tf | 11 - .../testdata/apply-invalid-index/main.tf | 7 - .../testdata/apply-issue19908/issue19908.tf | 3 - .../testdata/apply-local-val/child/child.tf | 4 - .../testdata/apply-local-val/main.tf | 10 - .../testdata/apply-local-val/outputs.tf | 9 - .../amodule/main.tf | 9 - .../apply-map-var-through-module/main.tf | 19 - .../terraform/testdata/apply-minimal/main.tf | 5 - .../testdata/apply-module-bool/child/main.tf | 7 - .../testdata/apply-module-bool/main.tf | 8 - .../testdata/apply-module-depends-on/main.tf | 32 - .../apply-module-depends-on/moda/main.tf | 11 - .../apply-module-depends-on/modb/main.tf | 11 - .../apply-module-destroy-order/child/main.tf | 7 - .../apply-module-destroy-order/main.tf | 8 - .../child/grandchild/main.tf | 1 - .../child/main.tf | 3 - .../main.tf | 7 - .../apply-module-only-provider/child/main.tf | 2 - .../apply-module-only-provider/main.tf | 5 - .../main.tf | 3 - .../apply-module-provider-alias/child/main.tf | 7 - .../apply-module-provider-alias/main.tf | 3 - .../child/main.tf | 3 - .../child/subchild/main.tf | 1 - .../main.tf | 3 - .../main.tf | 6 - .../child/main.tf | 7 - .../main.tf | 15 - .../apply-module-replace-cycle-cbd/main.tf | 8 - .../mod1/main.tf | 10 - .../mod2/main.tf | 8 - .../apply-module-replace-cycle/main.tf | 8 - .../apply-module-replace-cycle/mod1/main.tf | 7 - .../apply-module-replace-cycle/mod2/main.tf | 8 - .../child/main.tf | 6 - .../apply-module-var-resource-count/main.tf | 7 - .../testdata/apply-module/child/main.tf | 3 - .../terraform/testdata/apply-module/main.tf | 11 - .../main.tf | 12 - .../child/main.tf | 3 - .../main.tf | 9 - .../apply-multi-provider-destroy/main.tf | 9 - .../testdata/apply-multi-provider/main.tf | 7 - .../testdata/apply-multi-ref/main.tf | 8 - .../child/child.tf | 29 - .../apply-multi-var-comprehensive/root.tf | 74 - .../apply-multi-var-count-dec/main.tf | 12 - .../child/child.tf | 15 - .../apply-multi-var-missing-state/root.tf | 7 - .../apply-multi-var-order-interp/main.tf | 17 - .../testdata/apply-multi-var-order/main.tf | 12 - .../testdata/apply-multi-var/main.tf | 10 - .../testdata/apply-nullable-variables/main.tf | 28 - .../apply-nullable-variables/mod/main.tf | 59 - .../testdata/apply-orphan-resource/main.tf | 7 - .../testdata/apply-output-add-after/main.tf | 6 - .../apply-output-add-after/outputs.tf.json | 10 - .../testdata/apply-output-add-before/main.tf | 6 - .../apply-output-add-before/outputs.tf.json | 7 - .../testdata/apply-output-list/main.tf | 12 - .../testdata/apply-output-multi-index/main.tf | 12 - .../testdata/apply-output-multi/main.tf | 12 - .../apply-output-orphan-module/child/main.tf | 3 - .../apply-output-orphan-module/main.tf | 3 - .../testdata/apply-output-orphan/main.tf | 3 - .../terraform/testdata/apply-output/main.tf | 11 - .../apply-plan-connection-refs/main.tf | 18 - .../apply-provider-alias-configure/main.tf | 14 - .../testdata/apply-provider-alias/main.tf | 12 - .../testdata/apply-provider-computed/main.tf | 9 - .../child/main.tf | 5 - .../apply-provider-configure-disabled/main.tf | 7 - .../testdata/apply-provider-warning/main.tf | 1 - .../apply-provisioner-compute/main.tf | 13 - .../main.tf | 15 - .../apply-provisioner-destroy-fail/main.tf | 14 - .../apply-provisioner-destroy/main.tf | 18 - .../testdata/apply-provisioner-diff/main.tf | 4 - .../main.tf | 7 - .../apply-provisioner-fail-continue/main.tf | 7 - .../main.tf | 7 - .../apply-provisioner-fail-create/main.tf | 3 - .../testdata/apply-provisioner-fail/main.tf | 7 - .../apply-provisioner-for-each-self/main.tf | 8 - .../provisioner-interp-count.tf | 17 - .../apply-provisioner-module/child/main.tf | 5 - .../testdata/apply-provisioner-module/main.tf | 3 - .../main.tf | 9 - .../apply-provisioner-multi-self-ref/main.tf | 8 - .../apply-provisioner-resource-ref/main.tf | 7 - .../apply-provisioner-self-ref/main.tf | 7 - .../apply-provisioner-sensitive/main.tf | 18 - .../testdata/apply-ref-count/main.tf | 7 - .../testdata/apply-ref-existing/child/main.tf | 5 - .../testdata/apply-ref-existing/main.tf | 9 - .../apply-resource-count-one-list/main.tf | 7 - .../apply-resource-count-zero-list/main.tf | 7 - .../child/child/main.tf | 3 - .../child/main.tf | 3 - .../main.tf | 9 - .../main.tf | 1 - .../child/child/main.tf | 3 - .../child/main.tf | 8 - .../main.tf | 3 - .../child/main.tf | 3 - .../apply-resource-depends-on-module/main.tf | 9 - .../testdata/apply-resource-scale-in/main.tf | 13 - .../apply-taint-dep-requires-new/main.tf | 8 - .../testdata/apply-taint-dep/main.tf | 8 - .../terraform/testdata/apply-taint/main.tf | 3 - .../testdata/apply-tainted-targets/main.tf | 3 - .../testdata/apply-targeted-count/main.tf | 7 - .../apply-targeted-module-dep/child/main.tf | 5 - .../apply-targeted-module-dep/main.tf | 7 - .../child/main.tf | 3 - .../child/subchild/main.tf | 3 - .../apply-targeted-module-recursive/main.tf | 3 - .../child/main.tf | 7 - .../apply-targeted-module-resource/main.tf | 7 - .../child1/main.tf | 17 - .../child2/main.tf | 9 - .../main.tf | 37 - .../apply-targeted-module/child/main.tf | 7 - .../testdata/apply-targeted-module/main.tf | 11 - .../child/main.tf | 1 - .../main.tf | 5 - .../terraform/testdata/apply-targeted/main.tf | 7 - .../apply-terraform-workspace/main.tf | 3 - .../apply-unknown-interpolate/child/main.tf | 5 - .../apply-unknown-interpolate/main.tf | 6 - .../terraform/testdata/apply-unknown/main.tf | 3 - .../terraform/testdata/apply-unstable/main.tf | 3 - .../terraform/testdata/apply-vars-env/main.tf | 20 - .../terraform/testdata/apply-vars/main.tf | 33 - .../child/main.tf | 3 - .../context-required-version-module/main.tf | 3 - .../testdata/context-required-version/main.tf | 1 - .../data-source-read-with-plan-error/main.tf | 12 - .../destroy-module-with-provider/main.tf | 11 - .../destroy-module-with-provider/mod/main.tf | 6 - .../testdata/destroy-targeted/child/main.tf | 10 - .../testdata/destroy-targeted/main.tf | 12 - internal/terraform/testdata/empty/main.tf | 1 - .../testdata/eval-context-basic/child/main.tf | 7 - .../testdata/eval-context-basic/main.tf | 39 - .../terraform/testdata/graph-basic/main.tf | 24 - .../graph-builder-apply-basic/child/main.tf | 7 - .../graph-builder-apply-basic/main.tf | 9 - .../graph-builder-apply-count/main.tf | 7 - .../graph-builder-apply-dep-cbd/main.tf | 9 - .../graph-builder-apply-double-cbd/main.tf | 13 - .../A/main.tf | 9 - .../main.tf | 13 - .../graph-builder-apply-orphan-update/main.tf | 3 - .../graph-builder-apply-provisioner/main.tf | 3 - .../child1/main.tf | 11 - .../child2/main.tf | 1 - .../graph-builder-apply-target-module/main.tf | 10 - .../graph-builder-orphan-alias/main.tf | 3 - .../attr-as-blocks.tf | 8 - .../testdata/graph-builder-plan-basic/main.tf | 33 - .../graph-builder-plan-dynblock/dynblock.tf | 14 - .../child1/main.tf | 7 - .../child2/main.tf | 7 - .../main.tf | 9 - .../testdata/import-module/child/main.tf | 10 - .../import-module/child/submodule/main.tf | 3 - .../terraform/testdata/import-module/main.tf | 11 - .../testdata/import-provider-locals/main.tf | 13 - .../import-provider-resources/main.tf | 11 - .../testdata/import-provider-vars/main.tf | 9 - .../testdata/import-provider/main.tf | 6 - .../input-interpolate-var/child/main.tf | 6 - .../testdata/input-interpolate-var/main.tf | 7 - .../input-interpolate-var/source/main.tf | 3 - .../input-module-data-vars/child/main.tf | 5 - .../testdata/input-module-data-vars/main.tf | 8 - .../testdata/input-provider-multi/main.tf | 9 - .../input-provider-once/child/main.tf | 2 - .../testdata/input-provider-once/main.tf | 5 - .../testdata/input-provider-vars/main.tf | 5 - .../child/main.tf | 1 - .../main.tf | 7 - .../testdata/input-provider-with-vars/main.tf | 7 - .../terraform/testdata/input-provider/main.tf | 1 - .../testdata/input-submodule-count/main.tf | 4 - .../input-submodule-count/mod/main.tf | 11 - .../input-submodule-count/mod/submod/main.tf | 7 - .../testdata/input-variables/main.tf | 30 - .../testdata/issue-5254/step-0/main.tf | 12 - .../testdata/issue-5254/step-1/main.tf | 13 - .../terraform/testdata/issue-7824/main.tf | 6 - .../terraform/testdata/issue-9549/main.tf | 11 - .../terraform/testdata/issue-9549/mod/main.tf | 10 - .../nested-resource-count-plan/main.tf | 11 - .../block-nesting-group.tf | 2 - .../plan-cbd-depends-datasource/main.tf | 14 - .../testdata/plan-cbd-maintain-root/main.tf | 19 - internal/terraform/testdata/plan-cbd/main.tf | 5 - .../plan-close-module-provider/main.tf | 3 - .../plan-close-module-provider/mod/main.tf | 7 - .../main.tf | 10 - .../testdata/plan-computed-data-count/main.tf | 9 - .../plan-computed-data-resource/main.tf | 8 - .../plan-computed-in-function/main.tf | 7 - .../testdata/plan-computed-list/main.tf | 8 - .../plan-computed-multi-index/main.tf | 9 - .../plan-computed-value-in-map/main.tf | 16 - .../plan-computed-value-in-map/mod/main.tf | 8 - .../terraform/testdata/plan-computed/main.tf | 8 - .../plan-count-computed-module/child/main.tf | 5 - .../plan-count-computed-module/main.tf | 8 - .../testdata/plan-count-computed/main.tf | 8 - .../terraform/testdata/plan-count-dec/main.tf | 7 - .../terraform/testdata/plan-count-inc/main.tf | 8 - .../testdata/plan-count-index/main.tf | 4 - .../child/child/main.tf | 5 - .../child/main.tf | 6 - .../main.tf | 8 - .../plan-count-module-static/child/main.tf | 5 - .../testdata/plan-count-module-static/main.tf | 8 - .../testdata/plan-count-one-index/main.tf | 8 - .../plan-count-splat-reference/main.tf | 9 - .../terraform/testdata/plan-count-var/main.tf | 10 - .../testdata/plan-count-zero/main.tf | 8 - .../terraform/testdata/plan-count/main.tf | 8 - .../testdata/plan-data-depends-on/main.tf | 14 - .../main.tf | 6 - .../plan-destroy-interpolated-count/main.tf | 20 - .../mod/main.tf | 2 - .../terraform/testdata/plan-destroy/main.tf | 7 - .../terraform/testdata/plan-diffvar/main.tf | 7 - .../terraform/testdata/plan-empty/main.tf | 5 - .../testdata/plan-escaped-var/main.tf | 3 - .../plan-for-each-unknown-value/main.tf | 20 - .../terraform/testdata/plan-for-each/main.tf | 35 - internal/terraform/testdata/plan-good/main.tf | 7 - .../ignore-changes-in-map.tf | 13 - .../ignore-changes-sensitive.tf | 11 - .../plan-ignore-changes-wildcard/main.tf | 13 - .../plan-ignore-changes-with-flatmaps/main.tf | 15 - .../testdata/plan-ignore-changes/main.tf | 9 - .../testdata/plan-list-order/main.tf | 7 - .../testdata/plan-local-value-count/main.tf | 8 - .../testdata/plan-module-cycle/child/main.tf | 5 - .../testdata/plan-module-cycle/main.tf | 12 - .../plan-module-deadlock/child/main.tf | 7 - .../testdata/plan-module-deadlock/main.tf | 3 - .../plan-module-destroy-gh-1835/a/main.tf | 5 - .../plan-module-destroy-gh-1835/b/main.tf | 5 - .../plan-module-destroy-gh-1835/main.tf | 8 - .../child/main.tf | 8 - .../plan-module-destroy-multivar/main.tf | 4 - .../plan-module-destroy/child/main.tf | 3 - .../testdata/plan-module-destroy/main.tf | 7 - .../plan-module-input-computed/child/main.tf | 5 - .../plan-module-input-computed/main.tf | 8 - .../plan-module-input-var/child/main.tf | 5 - .../testdata/plan-module-input-var/main.tf | 10 - .../testdata/plan-module-input/child/main.tf | 5 - .../testdata/plan-module-input/main.tf | 8 - .../plan-module-map-literal/child/main.tf | 12 - .../testdata/plan-module-map-literal/main.tf | 9 - .../plan-module-multi-var/child/main.tf | 10 - .../testdata/plan-module-multi-var/main.tf | 9 - .../child/main.tf | 8 - .../plan-module-provider-defaults-var/main.tf | 11 - .../child/main.tf | 8 - .../plan-module-provider-defaults/main.tf | 11 - .../A/main.tf | 3 - .../B/main.tf | 3 - .../C/main.tf | 1 - .../plan-module-provider-inherit-deep/main.tf | 7 - .../child/main.tf | 3 - .../plan-module-provider-inherit/main.tf | 11 - .../plan-module-provider-var/child/main.tf | 9 - .../testdata/plan-module-provider-var/main.tf | 8 - .../plan-module-var-computed/child/main.tf | 7 - .../testdata/plan-module-var-computed/main.tf | 7 - .../inner/main.tf | 12 - .../main.tf | 7 - .../testdata/plan-module-var/child/main.tf | 7 - .../testdata/plan-module-var/main.tf | 7 - .../plan-module-variable-from-splat/main.tf | 9 - .../mod/main.tf | 12 - .../inner/main.tf | 13 - .../plan-module-wrong-var-type-nested/main.tf | 3 - .../middle/main.tf | 19 - .../plan-module-wrong-var-type/inner/main.tf | 13 - .../plan-module-wrong-var-type/main.tf | 10 - .../plan-modules-expand/child/main.tf | 12 - .../testdata/plan-modules-expand/main.tf | 29 - .../plan-modules-remove-provisioners/main.tf | 5 - .../parent/child/main.tf | 2 - .../parent/main.tf | 7 - .../testdata/plan-modules-remove/main.tf | 3 - .../testdata/plan-modules/child/main.tf | 3 - .../terraform/testdata/plan-modules/main.tf | 11 - .../terraform/testdata/plan-orphan/main.tf | 3 - .../terraform/testdata/plan-path-var/main.tf | 5 - .../testdata/plan-prevent-destroy-bad/main.tf | 7 - .../plan-prevent-destroy-count-bad/main.tf | 8 - .../plan-prevent-destroy-count-good/main.tf | 4 - .../plan-prevent-destroy-good/main.tf | 5 - .../terraform/testdata/plan-provider/main.tf | 7 - .../testdata/plan-provisioner-cycle/main.tf | 7 - .../testdata/plan-required-output/main.tf | 7 - .../testdata/plan-required-output/mod/main.tf | 7 - .../testdata/plan-required-whole-mod/main.tf | 17 - .../plan-required-whole-mod/mod/main.tf | 7 - .../testdata/plan-requires-replace/main.tf | 3 - .../testdata/plan-self-ref-multi-all/main.tf | 4 - .../testdata/plan-self-ref-multi/main.tf | 4 - .../terraform/testdata/plan-self-ref/main.tf | 3 - .../testdata/plan-shadow-uuid/main.tf | 3 - .../plan-taint-ignore-changes/main.tf | 7 - .../plan-taint-interpolated-count/main.tf | 7 - .../terraform/testdata/plan-taint/main.tf | 7 - .../plan-targeted-cross-module/A/main.tf | 7 - .../plan-targeted-cross-module/B/main.tf | 5 - .../plan-targeted-cross-module/main.tf | 8 - .../plan-targeted-module-orphan/main.tf | 6 - .../child/main.tf | 5 - .../main.tf | 12 - .../child1/main.tf | 7 - .../child2/main.tf | 7 - .../main.tf | 9 - .../testdata/plan-targeted-orphan/main.tf | 6 - .../testdata/plan-targeted-over-ten/main.tf | 3 - .../terraform/testdata/plan-targeted/main.tf | 12 - .../testdata/plan-targeted/mod/main.tf | 3 - .../plan-untargeted-resource-output/main.tf | 8 - .../mod/main.tf | 15 - .../testdata/plan-var-list-err/main.tf | 16 - .../child/main.tf | 13 - .../plan-variable-sensitivity-module/main.tf | 14 - .../plan-variable-sensitivity/main.tf | 8 - .../testdata/provider-meta-data-set/main.tf | 13 - .../provider-meta-data-set/my-module/main.tf | 9 - .../testdata/provider-meta-data-unset/main.tf | 7 - .../my-module/main.tf | 3 - .../testdata/provider-meta-set/main.tf | 13 - .../provider-meta-set/my-module/main.tf | 9 - .../testdata/provider-meta-unset/main.tf | 7 - .../provider-meta-unset/my-module/main.tf | 3 - .../testdata/provider-with-locals/main.tf | 11 - .../terraform/testdata/refresh-basic/main.tf | 1 - .../refresh-data-count/refresh-data-count.tf | 6 - .../refresh-data-module-var/child/main.tf | 6 - .../testdata/refresh-data-module-var/main.tf | 8 - .../testdata/refresh-data-ref-data/main.tf | 7 - .../refresh-data-resource-basic/main.tf | 5 - .../testdata/refresh-dynamic/main.tf | 3 - .../refresh-module-computed-var/child/main.tf | 5 - .../refresh-module-computed-var/main.tf | 8 - .../child/main.tf | 11 - .../main.tf | 8 - .../child/grandchild/main.tf | 3 - .../refresh-module-orphan/child/main.tf | 10 - .../testdata/refresh-module-orphan/main.tf | 10 - .../refresh-module-var-module/bar/main.tf | 3 - .../refresh-module-var-module/foo/main.tf | 7 - .../refresh-module-var-module/main.tf | 8 - .../testdata/refresh-modules/child/main.tf | 1 - .../testdata/refresh-modules/main.tf | 5 - .../testdata/refresh-no-state/main.tf | 3 - .../testdata/refresh-output-partial/main.tf | 7 - .../terraform/testdata/refresh-output/main.tf | 5 - .../testdata/refresh-schema-upgrade/main.tf | 2 - .../testdata/refresh-targeted-count/main.tf | 9 - .../testdata/refresh-targeted/main.tf | 8 - .../testdata/refresh-unknown-provider/main.tf | 4 - .../terraform/testdata/refresh-vars/main.tf | 5 - .../static-validate-refs.tf | 23 - .../main.tf | 11 - .../transform-cbd-destroy-edge-count/main.tf | 10 - .../transform-config-mode-data/main.tf | 3 - .../transform-destroy-cbd-edge-basic/main.tf | 9 - .../transform-destroy-cbd-edge-multi/main.tf | 15 - .../transform-destroy-edge-basic/main.tf | 5 - .../child/main.tf | 9 - .../main.tf | 4 - .../child/main.tf | 7 - .../transform-destroy-edge-module/main.tf | 7 - .../transform-destroy-edge-multi/main.tf | 9 - .../transform-destroy-edge-self-ref/main.tf | 5 - .../transform-module-var-basic/child/main.tf | 5 - .../transform-module-var-basic/main.tf | 4 - .../child/child/main.tf | 5 - .../transform-module-var-nested/child/main.tf | 6 - .../transform-module-var-nested/main.tf | 4 - .../testdata/transform-orphan-basic/main.tf | 1 - .../transform-orphan-count-empty/main.tf | 1 - .../testdata/transform-orphan-count/main.tf | 3 - .../testdata/transform-orphan-modules/main.tf | 1 - .../testdata/transform-provider-basic/main.tf | 2 - .../child/main.tf | 11 - .../transform-provider-fqns-module/main.tf | 11 - .../testdata/transform-provider-fqns/main.tf | 11 - .../child/grandchild/main.tf | 7 - .../child/main.tf | 10 - .../main.tf | 11 - .../transform-provider-inherit/child/main.tf | 7 - .../transform-provider-inherit/main.tf | 11 - .../main.tf | 3 - .../sub/main.tf | 5 - .../sub/subsub/main.tf | 2 - .../transform-provider-missing/main.tf | 3 - .../testdata/transform-provider-prune/main.tf | 2 - .../transform-provisioner-basic/main.tf | 3 - .../child/main.tf | 3 - .../transform-provisioner-module/main.tf | 7 - .../testdata/transform-root-basic/main.tf | 5 - .../testdata/transform-targets-basic/main.tf | 22 - .../child/child.tf | 14 - .../child/grandchild/grandchild.tf | 6 - .../transform-targets-downstream/main.tf | 18 - .../transform-trans-reduce-basic/main.tf | 10 - .../testdata/update-resource-provider/main.tf | 7 - .../testdata/validate-bad-count/main.tf | 3 - .../validate-bad-module-output/child/main.tf | 0 .../validate-bad-module-output/main.tf | 7 - .../testdata/validate-bad-pc/main.tf | 5 - .../testdata/validate-bad-prov-conf/main.tf | 9 - .../validate-bad-prov-connection/main.tf | 8 - .../testdata/validate-bad-rc/main.tf | 3 - .../validate-bad-resource-connection/main.tf | 8 - .../validate-bad-resource-count/main.tf | 22 - .../testdata/validate-bad-var/main.tf | 7 - .../validate-computed-in-function/main.tf | 7 - .../dest/main.tf | 5 - .../validate-computed-module-var-ref/main.tf | 8 - .../source/main.tf | 7 - .../testdata/validate-computed-var/main.tf | 9 - .../testdata/validate-count-computed/main.tf | 7 - .../testdata/validate-count-negative/main.tf | 3 - .../testdata/validate-count-variable/main.tf | 6 - .../validate-good-module/child/main.tf | 3 - .../testdata/validate-good-module/main.tf | 7 - .../terraform/testdata/validate-good/main.tf | 8 - .../validate-module-bad-rc/child/main.tf | 1 - .../testdata/validate-module-bad-rc/main.tf | 3 - .../validate-module-deps-cycle/a/main.tf | 5 - .../validate-module-deps-cycle/b/main.tf | 5 - .../validate-module-deps-cycle/main.tf | 8 - .../child/main.tf | 1 - .../validate-module-pc-inherit-unused/main.tf | 7 - .../validate-module-pc-inherit/child/main.tf | 3 - .../validate-module-pc-inherit/main.tf | 9 - .../validate-module-pc-vars/child/main.tf | 7 - .../testdata/validate-module-pc-vars/main.tf | 7 - .../validate-required-provider-config/main.tf | 20 - .../testdata/validate-required-var/main.tf | 5 - .../main.tf | 11 - .../validate-skipped-pc-empty/main.tf | 1 - .../testdata/validate-targeted/main.tf | 9 - .../main.tf | 5 - .../child/child.tf | 8 - .../validate-variable-custom-validations.tf | 10 - .../child/child.tf | 8 - .../validate-variable-custom-validations.tf | 5 - .../testdata/validate-variable-ref/main.tf | 5 - .../testdata/vars-basic-bool/main.tf | 10 - .../terraform/testdata/vars-basic/main.tf | 14 - internal/terraform/transform.go | 52 - .../transform_attach_config_provider.go | 16 - .../transform_attach_config_provider_meta.go | 15 - .../transform_attach_config_resource.go | 110 - internal/terraform/transform_attach_schema.go | 109 - internal/terraform/transform_attach_state.go | 68 - internal/terraform/transform_config.go | 122 - internal/terraform/transform_config_test.go | 86 - internal/terraform/transform_destroy_cbd.go | 150 - .../terraform/transform_destroy_cbd_test.go | 360 - internal/terraform/transform_destroy_edge.go | 374 - .../terraform/transform_destroy_edge_test.go | 595 - internal/terraform/transform_diff.go | 214 - internal/terraform/transform_diff_test.go | 167 - internal/terraform/transform_expand.go | 17 - .../terraform/transform_import_state_test.go | 167 - internal/terraform/transform_local.go | 42 - .../terraform/transform_module_expansion.go | 146 - .../terraform/transform_module_variable.go | 112 - .../transform_module_variable_test.go | 67 - internal/terraform/transform_orphan_count.go | 61 - .../terraform/transform_orphan_count_test.go | 306 - internal/terraform/transform_orphan_output.go | 62 - .../terraform/transform_orphan_resource.go | 108 - .../transform_orphan_resource_test.go | 326 - internal/terraform/transform_output.go | 73 - internal/terraform/transform_provider.go | 730 - internal/terraform/transform_provider_test.go | 491 - internal/terraform/transform_provisioner.go | 8 - internal/terraform/transform_reference.go | 557 - .../terraform/transform_reference_test.go | 319 - .../terraform/transform_removed_modules.go | 44 - .../terraform/transform_resource_count.go | 36 - internal/terraform/transform_root.go | 82 - internal/terraform/transform_root_test.go | 95 - internal/terraform/transform_state.go | 72 - internal/terraform/transform_targets.go | 159 - internal/terraform/transform_targets_test.go | 202 - .../transform_transitive_reduction.go | 20 - .../transform_transitive_reduction_test.go | 86 - internal/terraform/transform_variable.go | 43 - internal/terraform/transform_vertex.go | 44 - internal/terraform/transform_vertex_test.go | 58 - internal/terraform/ui_input.go | 32 - internal/terraform/ui_input_mock.go | 25 - internal/terraform/ui_input_prefix.go | 20 - internal/terraform/ui_input_prefix_test.go | 27 - internal/terraform/ui_output.go | 7 - internal/terraform/ui_output_callback.go | 9 - internal/terraform/ui_output_callback_test.go | 9 - internal/terraform/ui_output_mock.go | 21 - internal/terraform/ui_output_mock_test.go | 9 - internal/terraform/ui_output_provisioner.go | 19 - .../terraform/ui_output_provisioner_test.go | 36 - internal/terraform/update_state_hook.go | 19 - internal/terraform/update_state_hook_test.go | 33 - internal/terraform/upgrade_resource_state.go | 206 - .../terraform/upgrade_resource_state_test.go | 148 - internal/terraform/util.go | 75 - internal/terraform/util_test.go | 91 - internal/terraform/validate_selfref.go | 60 - internal/terraform/validate_selfref_test.go | 105 - internal/terraform/valuesourcetype_string.go | 59 - internal/terraform/variables.go | 315 - internal/terraform/variables_test.go | 148 - internal/terraform/version_required.go | 85 - internal/terraform/walkoperation_string.go | 30 - {internal/ipaddr => ipaddr}/LICENSE | 0 {internal/ipaddr => ipaddr}/PATENTS | 0 {internal/ipaddr => ipaddr}/README.md | 0 {internal/ipaddr => ipaddr}/doc.go | 0 {internal/ipaddr => ipaddr}/ip.go | 0 {internal/ipaddr => ipaddr}/ip_test.go | 0 {internal/ipaddr => ipaddr}/parse.go | 0 {internal/lang => lang}/blocktoattr/doc.go | 0 {internal/lang => lang}/blocktoattr/fixup.go | 2 +- .../blocktoattr/fixup_bench_test.go | 2 +- .../lang => lang}/blocktoattr/fixup_test.go | 2 +- {internal/lang => lang}/blocktoattr/schema.go | 2 +- .../lang => lang}/blocktoattr/variables.go | 2 +- .../blocktoattr/variables_test.go | 2 +- {internal/lang => lang}/data.go | 4 +- {internal/lang => lang}/data_test.go | 4 +- {internal/lang => lang}/doc.go | 0 {internal/lang => lang}/eval.go | 10 +- {internal/lang => lang}/eval_test.go | 6 +- {internal/lang => lang}/funcs/cidr.go | 2 +- {internal/lang => lang}/funcs/cidr_test.go | 0 {internal/lang => lang}/funcs/collection.go | 0 .../lang => lang}/funcs/collection_test.go | 2 +- {internal/lang => lang}/funcs/conversion.go | 4 +- .../lang => lang}/funcs/conversion_test.go | 2 +- {internal/lang => lang}/funcs/crypto.go | 0 {internal/lang => lang}/funcs/crypto_test.go | 0 {internal/lang => lang}/funcs/datetime.go | 0 .../lang => lang}/funcs/datetime_test.go | 0 {internal/lang => lang}/funcs/descriptions.go | 0 {internal/lang => lang}/funcs/encoding.go | 0 .../lang => lang}/funcs/encoding_test.go | 2 +- {internal/lang => lang}/funcs/filesystem.go | 0 .../lang => lang}/funcs/filesystem_test.go | 2 +- {internal/lang => lang}/funcs/number.go | 0 {internal/lang => lang}/funcs/number_test.go | 2 +- {internal/lang => lang}/funcs/redact.go | 2 +- {internal/lang => lang}/funcs/redact_test.go | 2 +- {internal/lang => lang}/funcs/sensitive.go | 2 +- .../lang => lang}/funcs/sensitive_test.go | 2 +- {internal/lang => lang}/funcs/string.go | 0 {internal/lang => lang}/funcs/string_test.go | 0 .../lang => lang}/funcs/testdata/bare.tmpl | 0 .../lang => lang}/funcs/testdata/func.tmpl | 0 .../lang => lang}/funcs/testdata/hello.tmpl | 0 .../lang => lang}/funcs/testdata/hello.txt | 0 .../lang => lang}/funcs/testdata/icon.png | Bin .../lang => lang}/funcs/testdata/list.tmpl | 0 .../funcs/testdata/recursive.tmpl | 0 .../funcs/testdata/unreadable/foobar | 0 {internal/lang => lang}/functions.go | 4 +- .../functions_descriptions_test.go | 2 +- {internal/lang => lang}/functions_test.go | 4 +- {internal/lang => lang}/globalref/analyzer.go | 6 +- .../analyzer_contributing_resources.go | 2 +- .../analyzer_contributing_resources_test.go | 2 +- .../globalref/analyzer_meta_references.go | 6 +- .../analyzer_meta_references_shortcuts.go | 4 +- .../analyzer_meta_references_test.go | 2 +- .../lang => lang}/globalref/analyzer_test.go | 12 +- {internal/lang => lang}/globalref/doc.go | 0 .../lang => lang}/globalref/reference.go | 4 +- .../testdata/assorted/assorted-root.tf | 0 .../testdata/assorted/child/assorted-child.tf | 0 .../compute/contributing-resources-compute.tf | 0 .../contributing-resources-root.tf | 0 .../network/contributing-resources-network.tf | 0 {internal/lang => lang}/marks/marks.go | 0 {internal/lang => lang}/references.go | 8 +- {internal/lang => lang}/scope.go | 4 +- .../testdata/functions-test/hello.tmpl | 0 .../testdata/functions-test/hello.txt | 0 .../functions-test/subdirectory/hello.tmpl | 0 .../functions-test/subdirectory/hello.txt | 0 {internal/lang => lang}/types/type_type.go | 0 {internal/lang => lang}/types/types.go | 0 .../helper/acctest/acctest.go | 0 .../helper/acctest/random.go | 0 .../helper/acctest/random_test.go | 0 .../helper/acctest/remotetests.go | 0 .../helper/hashcode/hashcode.go | 0 .../helper/hashcode/hashcode_test.go | 0 .../helper/schema/backend.go | 8 +- .../helper/schema/backend_test.go | 0 .../helper/schema/core_schema.go | 2 +- .../helper/schema/core_schema_test.go | 2 +- .../schema/data_source_resource_shim.go | 0 .../legacy => legacy}/helper/schema/doc.go | 0 .../legacy => legacy}/helper/schema/equal.go | 0 .../helper/schema/field_reader.go | 0 .../helper/schema/field_reader_config.go | 2 +- .../helper/schema/field_reader_config_test.go | 6 +- .../helper/schema/field_reader_diff.go | 2 +- .../helper/schema/field_reader_diff_test.go | 2 +- .../helper/schema/field_reader_map.go | 0 .../helper/schema/field_reader_map_test.go | 0 .../helper/schema/field_reader_multi.go | 0 .../helper/schema/field_reader_multi_test.go | 2 +- .../helper/schema/field_reader_test.go | 0 .../helper/schema/field_writer.go | 0 .../helper/schema/field_writer_map.go | 0 .../helper/schema/field_writer_map_test.go | 0 .../helper/schema/getsource_string.go | 0 .../helper/schema/provider.go | 4 +- .../helper/schema/provider_test.go | 4 +- .../helper/schema/provisioner.go | 4 +- .../helper/schema/provisioner_test.go | 2 +- .../helper/schema/resource.go | 2 +- .../helper/schema/resource_data.go | 2 +- .../helper/schema/resource_data_get_source.go | 0 .../helper/schema/resource_data_test.go | 2 +- .../helper/schema/resource_diff.go | 2 +- .../helper/schema/resource_diff_test.go | 4 +- .../helper/schema/resource_importer.go | 0 .../helper/schema/resource_test.go | 4 +- .../helper/schema/resource_timeout.go | 4 +- .../helper/schema/resource_timeout_test.go | 2 +- .../legacy => legacy}/helper/schema/schema.go | 4 +- .../helper/schema/schema_test.go | 6 +- .../helper/schema/serialize.go | 0 .../helper/schema/serialize_test.go | 0 .../legacy => legacy}/helper/schema/set.go | 2 +- .../helper/schema/set_test.go | 0 .../legacy => legacy}/helper/schema/shims.go | 6 +- .../helper/schema/shims_test.go | 12 +- .../helper/schema/testing.go | 2 +- .../helper/schema/valuetype.go | 0 .../helper/schema/valuetype_string.go | 0 .../terraform/context_components.go | 6 +- {internal/legacy => legacy}/terraform/diff.go | 6 +- .../legacy => legacy}/terraform/diff_test.go | 2 +- .../legacy => legacy}/terraform/features.go | 0 .../terraform/instancetype.go | 0 .../terraform/instancetype_string.go | 0 .../terraform/provider_mock.go | 4 +- .../terraform/provisioner_mock.go | 2 +- .../legacy => legacy}/terraform/resource.go | 6 +- .../terraform/resource_address.go | 4 +- .../terraform/resource_address_test.go | 4 +- .../terraform/resource_mode.go | 0 .../terraform/resource_mode_string.go | 0 .../terraform/resource_provider.go | 0 .../terraform/resource_provider_mock.go | 0 .../terraform/resource_provisioner.go | 4 +- .../terraform/resource_provisioner_mock.go | 2 +- .../terraform/resource_test.go | 4 +- .../legacy => legacy}/terraform/schemas.go | 12 +- .../legacy => legacy}/terraform/state.go | 12 +- .../terraform/state_filter.go | 0 .../legacy => legacy}/terraform/state_test.go | 4 +- .../terraform/state_upgrade_v1_to_v2.go | 0 .../terraform/state_upgrade_v2_to_v3.go | 0 .../legacy => legacy}/terraform/state_v1.go | 0 .../legacy => legacy}/terraform/testing.go | 0 .../legacy => legacy}/terraform/ui_input.go | 0 .../terraform/ui_input_mock.go | 0 .../terraform/ui_input_prefix.go | 0 .../terraform/ui_input_prefix_test.go | 0 .../legacy => legacy}/terraform/ui_output.go | 0 .../terraform/ui_output_callback.go | 0 .../terraform/ui_output_callback_test.go | 0 .../terraform/ui_output_mock.go | 0 .../terraform/ui_output_mock_test.go | 0 .../terraform/upgrade_state_v1_test.go | 0 .../terraform/upgrade_state_v2_test.go | 0 {internal/legacy => legacy}/terraform/util.go | 0 .../legacy => legacy}/terraform/util_test.go | 0 .../legacy => legacy}/terraform/version.go | 0 .../terraform/version_required.go | 4 +- {internal/logging => logging}/indent.go | 0 {internal/logging => logging}/indent_test.go | 0 {internal/logging => logging}/logging.go | 0 {internal/logging => logging}/panic.go | 0 {internal/logging => logging}/panic_test.go | 0 main.go | 16 +- {internal/modsdir => modsdir}/doc.go | 0 {internal/modsdir => modsdir}/manifest.go | 2 +- {internal/modsdir => modsdir}/paths.go | 0 .../moduledeps => moduledeps}/dependencies.go | 4 +- {internal/moduledeps => moduledeps}/doc.go | 0 {internal/moduledeps => moduledeps}/module.go | 2 +- .../moduledeps => moduledeps}/module_test.go | 4 +- .../moduletest => moduletest}/assertion.go | 2 +- {internal/moduletest => moduletest}/doc.go | 0 .../moduletest => moduletest}/provider.go | 8 +- .../provider_test.go | 2 +- .../status_string.go | 0 {internal/moduletest => moduletest}/suite.go | 0 {internal/plans => plans}/action.go | 0 {internal/plans => plans}/action_string.go | 0 {internal/plans => plans}/changes.go | 4 +- {internal/plans => plans}/changes_src.go | 4 +- {internal/plans => plans}/changes_state.go | 2 +- {internal/plans => plans}/changes_sync.go | 4 +- {internal/plans => plans}/changes_test.go | 4 +- {internal/plans => plans}/doc.go | 0 {internal/plans => plans}/dynamic_value.go | 0 .../plans => plans}/internal/planproto/doc.go | 0 .../internal/planproto/planfile.pb.go | 0 .../internal/planproto/planfile.proto | 0 {internal/plans => plans}/mode.go | 0 {internal/plans => plans}/mode_string.go | 0 {internal/plans => plans}/objchange/action.go | 2 +- .../plans => plans}/objchange/compatible.go | 4 +- .../objchange/compatible_test.go | 6 +- {internal/plans => plans}/objchange/doc.go | 0 {internal/plans => plans}/objchange/lcs.go | 0 .../plans => plans}/objchange/lcs_test.go | 2 +- .../objchange/normalize_obj.go | 2 +- .../objchange/normalize_obj_test.go | 2 +- .../plans => plans}/objchange/objchange.go | 2 +- .../objchange/objchange_test.go | 2 +- .../plans => plans}/objchange/plan_valid.go | 2 +- .../objchange/plan_valid_test.go | 4 +- {internal/plans => plans}/plan.go | 8 +- {internal/plans => plans}/plan_test.go | 2 +- .../planfile/config_snapshot.go | 2 +- .../planfile/config_snapshot_test.go | 2 +- {internal/plans => plans}/planfile/doc.go | 0 .../plans => plans}/planfile/planfile_test.go | 14 +- {internal/plans => plans}/planfile/reader.go | 12 +- .../.terraform/modules/child_a/child_a.tf | 0 .../modules/child_a/child_c/child_c.tf | 0 .../modules/child_b.child_d/child_d.tf | 0 .../.terraform/modules/child_b/child_b.tf | 0 .../.terraform/modules/modules.json | 0 .../planfile/testdata/test-config/root.tf | 0 {internal/plans => plans}/planfile/tfplan.go | 14 +- .../plans => plans}/planfile/tfplan_test.go | 12 +- {internal/plans => plans}/planfile/writer.go | 8 +- ...sourceinstancechangeactionreason_string.go | 0 .../plugin => plugin}/convert/diagnostics.go | 4 +- .../convert/diagnostics_test.go | 4 +- {internal/plugin => plugin}/convert/schema.go | 6 +- .../plugin => plugin}/convert/schema_test.go | 4 +- {internal/plugin => plugin}/discovery/find.go | 0 .../plugin => plugin}/discovery/find_test.go | 0 .../plugin => plugin}/discovery/get_cache.go | 0 .../discovery/get_cache_test.go | 0 {internal/plugin => plugin}/discovery/meta.go | 0 .../plugin => plugin}/discovery/meta_set.go | 0 .../discovery/meta_set_test.go | 0 .../plugin => plugin}/discovery/meta_test.go | 0 .../discovery/requirements.go | 0 .../discovery/requirements_test.go | 0 .../mockos_mockarch/terraform-foo-bar_v0.0.1 | 0 .../terraform-foo-missing-version | 0 .../terraform-notfoo-bar_v0.0.1 | 0 .../legacy-style-plugins/terraform-foo-bar | 0 .../legacy-style-plugins/terraform-foo-baz | 0 .../legacy-style-plugins/terraform-notfoo-bar | 0 .../discovery/testdata/not-a-dir | 0 .../terraform-provider-foo_v0.0.1_x4 | 0 .../plugin => plugin}/discovery/version.go | 0 .../discovery/version_set.go | 0 .../discovery/version_set_test.go | 0 .../discovery/version_test.go | 0 {internal/plugin => plugin}/grpc_error.go | 2 +- {internal/plugin => plugin}/grpc_provider.go | 8 +- .../plugin => plugin}/grpc_provider_test.go | 10 +- .../plugin => plugin}/grpc_provisioner.go | 8 +- .../grpc_provisioner_test.go | 8 +- plugin/mock_proto/generate.go | 3 + .../plugin => plugin}/mock_proto/mock.go | 4 +- {internal/plugin => plugin}/plugin.go | 2 +- {internal/plugin => plugin}/serve.go | 2 +- {internal/plugin => plugin}/ui_input.go | 2 +- {internal/plugin => plugin}/ui_input_test.go | 2 +- {internal/plugin => plugin}/ui_output.go | 2 +- {internal/plugin => plugin}/ui_output_test.go | 2 +- .../convert/diagnostics.go | 4 +- .../convert/diagnostics_test.go | 4 +- .../plugin6 => plugin6}/convert/schema.go | 6 +- .../convert/schema_test.go | 4 +- {internal/plugin6 => plugin6}/doc.go | 0 {internal/plugin6 => plugin6}/grpc_error.go | 2 +- .../plugin6 => plugin6}/grpc_provider.go | 8 +- .../plugin6 => plugin6}/grpc_provider_test.go | 10 +- .../mock_proto/generate.go | 2 +- .../plugin6 => plugin6}/mock_proto/mock.go | 4 +- {internal/plugin6 => plugin6}/serve.go | 2 +- plugins.go | 2 +- provider-simple-v6/main/main.go | 16 + .../provider.go | 4 +- provider-simple/main/main.go | 16 + .../provider.go | 4 +- .../main/main.go | 8 +- provider_source.go | 8 +- .../cached_provider.go | 4 +- .../cached_provider_test.go | 4 +- .../providercache => providercache}/dir.go | 4 +- .../dir_modify.go | 2 +- .../dir_modify_test.go | 4 +- .../dir_test.go | 4 +- .../providercache => providercache}/doc.go | 0 .../installer.go | 8 +- .../installer_events.go | 4 +- .../installer_events_test.go | 4 +- .../installer_test.go | 6 +- .../package_install.go | 6 +- .../terraform-provider-beep | 0 .../beep-provider/terraform-provider-beep | 0 .../linux_amd64/terraform-provider-legacy | 0 .../darwin_amd64/terraform-provider-null | 0 .../2.0.0/linux_amd64/terraform-provider-null | 0 .../hashicorp/null/invalid | 0 ...raform-provider-null_2.1.0_linux_amd64.zip | 0 .../null/terraform-provider-null_invalid.zip | 0 ...-provider-null_invalid_invalid_invalid.zip | 0 .../terraform-provider-random-beta | 0 .../linux_amd64/terraform-provider-random | 0 .../executable/2.0.0/linux_amd64/executable | 0 .../0.1.0-alpha.2/darwin_amd64/extra-data.txt | 0 .../terraform-provider-happycloud | 0 ...raform-provider-null_2.1.0_linux_amd64.zip | Bin .../addressed_types.go | 2 +- .../addressed_types_test.go | 2 +- {internal/providers => providers}/doc.go | 0 {internal/providers => providers}/factory.go | 0 {internal/providers => providers}/provider.go | 4 +- {internal/providers => providers}/schemas.go | 4 +- .../main/main.go | 8 +- .../provisioners => provisioners}/doc.go | 0 .../provisioners => provisioners}/factory.go | 0 .../provisioner.go | 4 +- .../move_execute.go | 8 +- .../move_execute_test.go | 4 +- .../move_statement.go | 8 +- .../move_statement_test.go | 6 +- .../move_validate.go | 10 +- .../move_validate_test.go | 14 +- .../child/move-statement-implied.tf | 0 .../move-statement-implied.tf | 0 .../child/move-validate-child.tf | 0 .../move-validate-zoo/move-validate-root.tf | 0 {internal/registry => registry}/client.go | 8 +- .../registry => registry}/client_test.go | 6 +- {internal/registry => registry}/errors.go | 2 +- .../regsrc/friendly_host.go | 0 .../regsrc/friendly_host_test.go | 0 .../registry => registry}/regsrc/module.go | 2 +- .../regsrc/module_test.go | 0 .../registry => registry}/regsrc/regsrc.go | 0 .../registry => registry}/response/module.go | 0 .../response/module_list.go | 0 .../response/module_provider.go | 0 .../response/module_versions.go | 0 .../response/pagination.go | 0 .../response/pagination_test.go | 0 .../response/redirect.go | 0 .../test/mock_registry.go | 6 +- {internal/repl => repl}/format.go | 2 +- {internal/repl => repl}/format_test.go | 2 +- {internal/repl => repl}/repl.go | 0 {internal/repl => repl}/session.go | 8 +- {internal/repl => repl}/session_test.go | 16 +- .../testdata/config-fixture/child/empty.tf | 0 .../testdata/config-fixture/repl_test.tf | 0 {internal/replacefile => replacefile}/doc.go | 0 .../replacefile_unix.go | 0 .../replacefile_windows.go | 0 .../replacefile => replacefile}/writefile.go | 0 {internal/states => states}/checks.go | 4 +- {internal/states => states}/doc.go | 0 .../states => states}/instance_generation.go | 0 .../states => states}/instance_object.go | 2 +- .../states => states}/instance_object_src.go | 4 +- .../states => states}/instance_object_test.go | 2 +- {internal/states => states}/module.go | 2 +- .../states => states}/objectstatus_string.go | 0 {internal/states => states}/output_value.go | 2 +- {internal/states => states}/remote/remote.go | 2 +- .../states => states}/remote/remote_test.go | 0 {internal/states => states}/remote/state.go | 8 +- .../states => states}/remote/state_test.go | 8 +- {internal/states => states}/remote/testing.go | 4 +- {internal/states => states}/resource.go | 2 +- {internal/states => states}/resource_test.go | 0 {internal/states => states}/state.go | 4 +- {internal/states => states}/state_deepcopy.go | 2 +- {internal/states => states}/state_equal.go | 2 +- {internal/states => states}/state_string.go | 4 +- {internal/states => states}/state_test.go | 4 +- .../statefile/diagnostics.go | 2 +- {internal/states => states}/statefile/doc.go | 0 {internal/states => states}/statefile/file.go | 2 +- .../statefile/marshal_equal.go | 2 +- {internal/states => states}/statefile/read.go | 2 +- .../statefile/roundtrip_test.go | 0 .../testdata/roundtrip/v1-simple.in.tfstate | 0 .../testdata/roundtrip/v1-simple.out.tfstate | 0 .../testdata/roundtrip/v3-bigint.in.tfstate | 0 .../testdata/roundtrip/v3-bigint.out.tfstate | 0 .../testdata/roundtrip/v3-builtin.in.tfstate | 0 .../testdata/roundtrip/v3-builtin.out.tfstate | 0 .../testdata/roundtrip/v3-grabbag.in.tfstate | 0 .../testdata/roundtrip/v3-grabbag.out.tfstate | 0 .../roundtrip/v3-invalid-depends.in.tfstate | 0 .../roundtrip/v3-invalid-depends.out.tfstate | 0 .../testdata/roundtrip/v3-simple.in.tfstate | 0 .../testdata/roundtrip/v3-simple.out.tfstate | 0 .../testdata/roundtrip/v4-cbd.in.tfstate | 0 .../testdata/roundtrip/v4-cbd.out.tfstate | 0 .../testdata/roundtrip/v4-foreach.in.tfstate | 0 .../testdata/roundtrip/v4-foreach.out.tfstate | 0 .../testdata/roundtrip/v4-future.in.tfstate | 0 .../testdata/roundtrip/v4-future.out.tfstate | 0 .../roundtrip/v4-legacy-foreach.in.tfstate | 0 .../roundtrip/v4-legacy-foreach.out.tfstate | 0 .../roundtrip/v4-legacy-modules.in.tfstate | 0 .../roundtrip/v4-legacy-modules.out.tfstate | 0 .../roundtrip/v4-legacy-simple.in.tfstate | 0 .../roundtrip/v4-legacy-simple.out.tfstate | 0 .../testdata/roundtrip/v4-modules.in.tfstate | 0 .../testdata/roundtrip/v4-modules.out.tfstate | 0 .../testdata/roundtrip/v4-simple.in.tfstate | 0 .../testdata/roundtrip/v4-simple.out.tfstate | 0 .../states => states}/statefile/version0.go | 0 .../states => states}/statefile/version1.go | 2 +- .../statefile/version1_upgrade.go | 0 .../states => states}/statefile/version2.go | 2 +- .../statefile/version2_upgrade.go | 0 .../states => states}/statefile/version3.go | 2 +- .../statefile/version3_upgrade.go | 8 +- .../states => states}/statefile/version4.go | 10 +- .../statefile/version4_test.go | 2 +- .../states => states}/statefile/write.go | 0 {internal/states => states}/statemgr/doc.go | 0 .../states => states}/statemgr/filesystem.go | 6 +- .../statemgr/filesystem_lock_unix.go | 0 .../statemgr/filesystem_lock_windows.go | 0 .../statemgr/filesystem_test.go | 6 +- .../states => states}/statemgr/helper.go | 6 +- .../states => states}/statemgr/lineage.go | 0 {internal/states => states}/statemgr/lock.go | 4 +- .../states => states}/statemgr/lock_test.go | 0 .../states => states}/statemgr/locker.go | 0 .../states => states}/statemgr/migrate.go | 2 +- .../statemgr/migrate_test.go | 6 +- .../states => states}/statemgr/persistent.go | 4 +- {internal/states => states}/statemgr/plan.go | 4 +- .../statemgr/snapshotmetarel_string.go | 0 .../states => states}/statemgr/statemgr.go | 0 .../statemgr/statemgr_fake.go | 4 +- .../statemgr/statemgr_test.go | 2 +- .../statemgr/testdata/lockstate.go | 2 +- .../states => states}/statemgr/testing.go | 6 +- .../states => states}/statemgr/transient.go | 2 +- .../statemgr/transient_inmem.go | 2 +- {internal/states => states}/sync.go | 4 +- .../terminal => terminal}/impl_others.go | 0 .../terminal => terminal}/impl_windows.go | 0 {internal/terminal => terminal}/stream.go | 0 {internal/terminal => terminal}/streams.go | 0 .../terminal => terminal}/streams_test.go | 0 {internal/terminal => terminal}/testing.go | 0 .../tfdiags => tfdiags}/config_traversals.go | 0 .../consolidate_warnings.go | 0 .../consolidate_warnings_test.go | 30 +- {internal/tfdiags => tfdiags}/contextual.go | 0 .../tfdiags => tfdiags}/contextual_test.go | 0 {internal/tfdiags => tfdiags}/diagnostic.go | 0 .../tfdiags => tfdiags}/diagnostic_base.go | 0 .../tfdiags => tfdiags}/diagnostic_extra.go | 0 {internal/tfdiags => tfdiags}/diagnostics.go | 0 .../tfdiags => tfdiags}/diagnostics_test.go | 0 {internal/tfdiags => tfdiags}/doc.go | 0 {internal/tfdiags => tfdiags}/error.go | 0 {internal/tfdiags => tfdiags}/hcl.go | 0 {internal/tfdiags => tfdiags}/hcl_test.go | 0 {internal/tfdiags => tfdiags}/rpc_friendly.go | 18 +- .../tfdiags => tfdiags}/rpc_friendly_test.go | 6 +- .../tfdiags => tfdiags}/severity_string.go | 0 .../tfdiags => tfdiags}/simple_warning.go | 0 {internal/tfdiags => tfdiags}/source_range.go | 0 {internal/tfdiags => tfdiags}/sourceless.go | 0 .../tfplugin5 => tfplugin5}/tfplugin5.pb.go | 0 .../tfplugin5 => tfplugin5}/tfplugin5.proto | 0 .../tfplugin6 => tfplugin6}/tfplugin6.pb.go | 0 .../tfplugin6 => tfplugin6}/tfplugin6.proto | 0 working_dir.go | 2 +- 2770 files changed, 2119 insertions(+), 72645 deletions(-) rename {internal/addrs => addrs}/check.go (99%) rename {internal/addrs => addrs}/checkablekind_string.go (100%) rename {internal/addrs => addrs}/checktype_string.go (100%) rename {internal/addrs => addrs}/count_attr.go (100%) rename {internal/addrs => addrs}/doc.go (100%) rename {internal/addrs => addrs}/for_each_attr.go (100%) rename {internal/addrs => addrs}/input_variable.go (100%) rename {internal/addrs => addrs}/instance_key.go (100%) rename {internal/addrs => addrs}/instance_key_test.go (100%) rename {internal/addrs => addrs}/local_value.go (100%) rename {internal/addrs => addrs}/map.go (100%) rename {internal/addrs => addrs}/map_test.go (100%) rename {internal/addrs => addrs}/module.go (100%) rename {internal/addrs => addrs}/module_call.go (100%) rename {internal/addrs => addrs}/module_instance.go (99%) rename {internal/addrs => addrs}/module_instance_test.go (100%) rename {internal/addrs => addrs}/module_package.go (100%) rename {internal/addrs => addrs}/module_source.go (99%) rename {internal/addrs => addrs}/module_source_test.go (100%) rename {internal/addrs => addrs}/module_test.go (100%) rename {internal/addrs => addrs}/move_endpoint.go (99%) rename {internal/addrs => addrs}/move_endpoint_kind.go (100%) rename {internal/addrs => addrs}/move_endpoint_module.go (99%) rename {internal/addrs => addrs}/move_endpoint_module_test.go (99%) rename {internal/addrs => addrs}/move_endpoint_test.go (100%) rename {internal/addrs => addrs}/moveable.go (100%) rename {internal/addrs => addrs}/moveendpointkind_string.go (100%) rename {internal/addrs => addrs}/output_value.go (99%) rename {internal/addrs => addrs}/output_value_test.go (100%) rename {internal/addrs => addrs}/parse_ref.go (99%) rename {internal/addrs => addrs}/parse_ref_test.go (99%) rename {internal/addrs => addrs}/parse_target.go (99%) rename {internal/addrs => addrs}/parse_target_test.go (99%) rename {internal/addrs => addrs}/path_attr.go (100%) rename {internal/addrs => addrs}/provider.go (99%) rename {internal/addrs => addrs}/provider_config.go (99%) rename {internal/addrs => addrs}/provider_config_test.go (100%) rename {internal/addrs => addrs}/provider_test.go (100%) rename {internal/addrs => addrs}/referenceable.go (100%) rename {internal/addrs => addrs}/resource.go (100%) rename {internal/addrs => addrs}/resource_phase.go (100%) rename {internal/addrs => addrs}/resource_test.go (100%) rename {internal/addrs => addrs}/resourcemode_string.go (100%) rename {internal/addrs => addrs}/self.go (100%) rename {internal/addrs => addrs}/set.go (100%) rename {internal/addrs => addrs}/target_test.go (100%) rename {internal/addrs => addrs}/targetable.go (100%) rename {internal/addrs => addrs}/terraform_attr.go (100%) rename {internal/addrs => addrs}/unique_key.go (100%) rename {internal/addrs => addrs}/unique_key_test.go (100%) rename {internal/backend => backend}/backend.go (95%) rename {internal/backend => backend}/backend_test.go (100%) rename {internal/backend => backend}/cli.go (97%) rename {internal/backend => backend}/init/deprecate_test.go (89%) rename {internal/backend => backend}/init/init.go (81%) rename {internal/backend => backend}/init/init_test.go (100%) rename {internal/backend => backend}/local/backend.go (97%) rename {internal/backend => backend}/local/backend_apply.go (95%) rename {internal/backend => backend}/local/backend_apply_test.go (92%) rename {internal/backend => backend}/local/backend_local.go (97%) rename {internal/backend => backend}/local/backend_local_test.go (88%) rename {internal/backend => backend}/local/backend_plan.go (93%) rename {internal/backend => backend}/local/backend_plan_test.go (97%) rename {internal/backend => backend}/local/backend_refresh.go (91%) rename {internal/backend => backend}/local/backend_refresh_test.go (92%) rename {internal/backend => backend}/local/backend_test.go (96%) rename {internal/backend => backend}/local/cli.go (94%) rename {internal/backend => backend}/local/hook_state.go (77%) rename {internal/backend => backend}/local/hook_state_test.go (82%) rename {internal/backend => backend}/local/local_test.go (68%) rename {internal/backend => backend}/local/testdata/apply-empty/hello.txt (100%) rename {internal/backend => backend}/local/testdata/apply-error/main.tf (100%) rename {internal/backend => backend}/local/testdata/apply/main.tf (100%) rename {internal/backend => backend}/local/testdata/destroy-with-ds/main.tf (100%) rename {internal/backend => backend}/local/testdata/empty/.gitignore (100%) rename {internal/backend => backend}/local/testdata/invalid/invalid.tf (100%) rename {internal/backend => backend}/local/testdata/plan-cbd/main.tf (100%) rename {internal/backend => backend}/local/testdata/plan-module-outputs-changed/main.tf (100%) rename {internal/backend => backend}/local/testdata/plan-module-outputs-changed/mod/main.tf (100%) rename {internal/backend => backend}/local/testdata/plan-outputs-changed/main.tf (100%) rename {internal/backend => backend}/local/testdata/plan-outputs-changed/submodule/main.tf (100%) rename {internal/backend => backend}/local/testdata/plan/main.tf (100%) rename {internal/backend => backend}/local/testdata/refresh-provider-config/main.tf (100%) rename {internal/backend => backend}/local/testdata/refresh-var-unset/main.tf (100%) rename {internal/backend => backend}/local/testdata/refresh/main.tf (100%) rename {internal/backend => backend}/local/testing.go (95%) rename {internal/backend => backend}/operation_type.go (100%) rename {internal/backend => backend}/operationtype_string.go (100%) rename {internal/backend => backend}/remote-state/azure/arm_client.go (99%) rename {internal/backend => backend}/remote-state/azure/backend.go (98%) rename {internal/backend => backend}/remote-state/azure/backend_state.go (94%) rename {internal/backend => backend}/remote-state/azure/backend_test.go (99%) rename {internal/backend => backend}/remote-state/azure/client.go (98%) rename {internal/backend => backend}/remote-state/azure/client_test.go (98%) rename {internal/backend => backend}/remote-state/azure/helpers_test.go (100%) rename {internal/backend => backend}/remote-state/azure/sender.go (97%) rename {internal/backend => backend}/remote-state/consul/backend.go (97%) rename {internal/backend => backend}/remote-state/consul/backend_state.go (94%) rename {internal/backend => backend}/remote-state/consul/backend_test.go (97%) rename {internal/backend => backend}/remote-state/consul/client.go (99%) rename {internal/backend => backend}/remote-state/consul/client_test.go (98%) rename {internal/backend => backend}/remote-state/cos/backend.go (98%) rename {internal/backend => backend}/remote-state/cos/backend_state.go (95%) rename {internal/backend => backend}/remote-state/cos/backend_test.go (98%) rename {internal/backend => backend}/remote-state/cos/client.go (98%) rename {internal/backend => backend}/remote-state/cos/transport.go (100%) rename {internal/backend => backend}/remote-state/gcs/backend.go (97%) rename {internal/backend => backend}/remote-state/gcs/backend_state.go (94%) rename {internal/backend => backend}/remote-state/gcs/backend_test.go (98%) rename {internal/backend => backend}/remote-state/gcs/client.go (97%) rename {internal/backend => backend}/remote-state/http/backend.go (96%) rename {internal/backend => backend}/remote-state/http/backend_test.go (98%) rename {internal/backend => backend}/remote-state/http/client.go (98%) rename {internal/backend => backend}/remote-state/http/client_test.go (98%) rename {internal/backend => backend}/remote-state/http/mock_server_test.go (100%) rename {internal/backend => backend}/remote-state/http/server_test.go (98%) rename {internal/backend => backend}/remote-state/http/testdata/certs/ca.cert.pem (100%) rename {internal/backend => backend}/remote-state/http/testdata/certs/ca.key (100%) rename {internal/backend => backend}/remote-state/http/testdata/certs/client.crt (100%) rename {internal/backend => backend}/remote-state/http/testdata/certs/client.csr (100%) rename {internal/backend => backend}/remote-state/http/testdata/certs/client.key (100%) rename {internal/backend => backend}/remote-state/http/testdata/certs/server.crt (100%) rename {internal/backend => backend}/remote-state/http/testdata/certs/server.csr (100%) rename {internal/backend => backend}/remote-state/http/testdata/certs/server.key (100%) rename {internal/backend => backend}/remote-state/http/testdata/gencerts.sh (100%) rename {internal/backend => backend}/remote-state/inmem/backend.go (93%) rename {internal/backend => backend}/remote-state/inmem/backend_test.go (89%) rename {internal/backend => backend}/remote-state/inmem/client.go (86%) rename {internal/backend => backend}/remote-state/inmem/client_test.go (86%) rename {internal/backend => backend}/remote-state/kubernetes/backend.go (99%) rename {internal/backend => backend}/remote-state/kubernetes/backend_state.go (94%) rename {internal/backend => backend}/remote-state/kubernetes/backend_test.go (97%) rename {internal/backend => backend}/remote-state/kubernetes/client.go (98%) rename {internal/backend => backend}/remote-state/kubernetes/client_test.go (94%) rename {internal/backend => backend}/remote-state/oss/backend.go (99%) rename {internal/backend => backend}/remote-state/oss/backend_state.go (95%) rename {internal/backend => backend}/remote-state/oss/backend_test.go (98%) rename {internal/backend => backend}/remote-state/oss/client.go (98%) rename {internal/backend => backend}/remote-state/oss/client_test.go (97%) rename {internal/backend => backend}/remote-state/pg/backend.go (96%) rename {internal/backend => backend}/remote-state/pg/backend_state.go (92%) rename {internal/backend => backend}/remote-state/pg/backend_test.go (98%) rename {internal/backend => backend}/remote-state/pg/client.go (97%) rename {internal/backend => backend}/remote-state/pg/client_test.go (94%) rename {internal/backend => backend}/remote-state/s3/backend.go (98%) rename {internal/backend => backend}/remote-state/s3/backend_state.go (95%) rename {internal/backend => backend}/remote-state/s3/backend_test.go (99%) rename {internal/backend => backend}/remote-state/s3/client.go (98%) rename {internal/backend => backend}/remote-state/s3/client_test.go (97%) rename {internal/backend => backend}/remote/backend.go (98%) rename {internal/backend => backend}/remote/backend_apply.go (97%) rename {internal/backend => backend}/remote/backend_apply_test.go (98%) rename {internal/backend => backend}/remote/backend_common.go (98%) rename {internal/backend => backend}/remote/backend_context.go (97%) rename {internal/backend => backend}/remote/backend_context_test.go (96%) rename {internal/backend => backend}/remote/backend_plan.go (98%) rename {internal/backend => backend}/remote/backend_plan_test.go (98%) rename {internal/backend => backend}/remote/backend_state.go (95%) rename {internal/backend => backend}/remote/backend_state_test.go (83%) rename {internal/backend => backend}/remote/backend_test.go (99%) rename {internal/backend => backend}/remote/cli.go (86%) rename {internal/backend => backend}/remote/colorize.go (100%) rename {internal/backend => backend}/remote/remote_test.go (88%) rename {internal/backend => backend}/remote/testdata/apply-destroy/apply.log (100%) rename {internal/backend => backend}/remote/testdata/apply-destroy/main.tf (100%) rename {internal/backend => backend}/remote/testdata/apply-destroy/plan.log (100%) rename {internal/backend => backend}/remote/testdata/apply-no-changes/main.tf (100%) rename {internal/backend => backend}/remote/testdata/apply-no-changes/plan.log (100%) rename {internal/backend => backend}/remote/testdata/apply-no-changes/policy.log (100%) rename {internal/backend => backend}/remote/testdata/apply-policy-hard-failed/main.tf (100%) rename {internal/backend => backend}/remote/testdata/apply-policy-hard-failed/plan.log (100%) rename {internal/backend => backend}/remote/testdata/apply-policy-hard-failed/policy.log (100%) rename {internal/backend => backend}/remote/testdata/apply-policy-passed/apply.log (100%) rename {internal/backend => backend}/remote/testdata/apply-policy-passed/main.tf (100%) rename {internal/backend => backend}/remote/testdata/apply-policy-passed/plan.log (100%) rename {internal/backend => backend}/remote/testdata/apply-policy-passed/policy.log (100%) rename {internal/backend => backend}/remote/testdata/apply-policy-soft-failed/apply.log (100%) rename {internal/backend => backend}/remote/testdata/apply-policy-soft-failed/main.tf (100%) rename {internal/backend => backend}/remote/testdata/apply-policy-soft-failed/plan.log (100%) rename {internal/backend => backend}/remote/testdata/apply-policy-soft-failed/policy.log (100%) rename {internal/backend => backend}/remote/testdata/apply-variables/apply.log (100%) rename {internal/backend => backend}/remote/testdata/apply-variables/main.tf (100%) rename {internal/backend => backend}/remote/testdata/apply-variables/plan.log (100%) rename {internal/backend => backend}/remote/testdata/apply-with-error/main.tf (100%) rename {internal/backend => backend}/remote/testdata/apply-with-error/plan.log (100%) rename {internal/backend => backend}/remote/testdata/apply/apply.log (100%) rename {internal/backend => backend}/remote/testdata/apply/main.tf (100%) rename {internal/backend => backend}/remote/testdata/apply/plan.log (100%) rename {internal/backend => backend}/remote/testdata/empty/.gitignore (100%) rename {internal/backend => backend}/remote/testdata/plan-cost-estimation/ce.log (100%) rename {internal/backend => backend}/remote/testdata/plan-cost-estimation/cost-estimate.log (100%) rename {internal/backend => backend}/remote/testdata/plan-cost-estimation/main.tf (100%) rename {internal/backend => backend}/remote/testdata/plan-cost-estimation/plan.log (100%) rename {internal/backend => backend}/remote/testdata/plan-long-line/main.tf (100%) rename {internal/backend => backend}/remote/testdata/plan-long-line/plan.log (100%) rename {internal/backend => backend}/remote/testdata/plan-no-changes/main.tf (100%) rename {internal/backend => backend}/remote/testdata/plan-no-changes/plan.log (100%) rename {internal/backend => backend}/remote/testdata/plan-no-changes/policy.log (100%) rename {internal/backend => backend}/remote/testdata/plan-policy-hard-failed/main.tf (100%) rename {internal/backend => backend}/remote/testdata/plan-policy-hard-failed/plan.log (100%) rename {internal/backend => backend}/remote/testdata/plan-policy-hard-failed/policy.log (100%) rename {internal/backend => backend}/remote/testdata/plan-policy-passed/main.tf (100%) rename {internal/backend => backend}/remote/testdata/plan-policy-passed/plan.log (100%) rename {internal/backend => backend}/remote/testdata/plan-policy-passed/policy.log (100%) rename {internal/backend => backend}/remote/testdata/plan-policy-soft-failed/main.tf (100%) rename {internal/backend => backend}/remote/testdata/plan-policy-soft-failed/plan.log (100%) rename {internal/backend => backend}/remote/testdata/plan-policy-soft-failed/policy.log (100%) rename {internal/backend => backend}/remote/testdata/plan-variables/main.tf (100%) rename {internal/backend => backend}/remote/testdata/plan-variables/plan.log (100%) rename {internal/backend => backend}/remote/testdata/plan-with-error/main.tf (100%) rename {internal/backend => backend}/remote/testdata/plan-with-error/plan.log (100%) rename {internal/backend => backend}/remote/testdata/plan-with-working-directory/terraform/main.tf (100%) rename {internal/backend => backend}/remote/testdata/plan-with-working-directory/terraform/plan.log (100%) rename {internal/backend => backend}/remote/testdata/plan/main.tf (100%) rename {internal/backend => backend}/remote/testdata/plan/plan.log (100%) rename {internal/backend => backend}/remote/testdata/variables/main.tf (100%) rename {internal/backend => backend}/remote/testing.go (93%) rename {internal/backend => backend}/testing.go (97%) rename {internal/backend => backend}/unparsed_value.go (98%) rename {internal/backend => backend}/unparsed_value_test.go (98%) rename {internal/builtin => builtin}/providers/README (100%) rename {internal/builtin => builtin}/providers/terraform/data_source_state.go (95%) rename {internal/builtin => builtin}/providers/terraform/data_source_state_test.go (97%) rename {internal/builtin => builtin}/providers/terraform/provider.go (98%) rename {internal/builtin => builtin}/providers/terraform/provider_test.go (59%) rename {internal/builtin => builtin}/providers/terraform/resource_data.go (96%) rename {internal/builtin => builtin}/providers/terraform/resource_data_test.go (99%) rename {internal/builtin => builtin}/providers/terraform/testdata/basic.tfstate (100%) rename {internal/builtin => builtin}/providers/terraform/testdata/complex_outputs.tfstate (100%) rename {internal/builtin => builtin}/providers/terraform/testdata/empty.tfstate (100%) rename {internal/builtin => builtin}/providers/terraform/testdata/null_outputs.tfstate (100%) rename {internal/builtin => builtin}/provisioners/file/resource_provisioner.go (95%) rename {internal/builtin => builtin}/provisioners/file/resource_provisioner_test.go (98%) rename {internal/builtin => builtin}/provisioners/local-exec/resource_provisioner.go (97%) rename {internal/builtin => builtin}/provisioners/local-exec/resource_provisioner_test.go (99%) rename {internal/builtin => builtin}/provisioners/remote-exec/resource_provisioner.go (95%) rename {internal/builtin => builtin}/provisioners/remote-exec/resource_provisioner_test.go (97%) rename {internal/builtin => builtin}/provisioners/remote-exec/testdata/script1.sh (100%) rename {internal/checks => checks}/doc.go (100%) rename {internal/checks => checks}/state.go (98%) rename {internal/checks => checks}/state_init.go (95%) rename {internal/checks => checks}/state_report.go (98%) rename {internal/checks => checks}/state_test.go (97%) rename {internal/checks => checks}/status.go (100%) rename {internal/checks => checks}/status_string.go (100%) rename {internal/checks => checks}/testdata/happypath/checks-happypath.tf (100%) rename {internal/checks => checks}/testdata/happypath/child/checks-happypath-child.tf (100%) rename {internal/cloud => cloud}/backend.go (98%) rename {internal/cloud => cloud}/backend_apply.go (96%) rename {internal/cloud => cloud}/backend_apply_test.go (98%) rename {internal/cloud => cloud}/backend_cli.go (81%) rename {internal/cloud => cloud}/backend_colorize.go (100%) rename {internal/cloud => cloud}/backend_common.go (98%) rename {internal/cloud => cloud}/backend_context.go (97%) rename {internal/cloud => cloud}/backend_context_test.go (95%) rename {internal/cloud => cloud}/backend_plan.go (98%) rename {internal/cloud => cloud}/backend_plan_test.go (98%) rename {internal/cloud => cloud}/backend_refresh_test.go (83%) rename {internal/cloud => cloud}/backend_taskStage_policyEvaluation.go (100%) rename {internal/cloud => cloud}/backend_taskStage_policyEvaluation_test.go (100%) rename {internal/cloud => cloud}/backend_taskStage_taskResults.go (100%) rename {internal/cloud => cloud}/backend_taskStage_taskResults_test.go (100%) rename {internal/cloud => cloud}/backend_taskStages.go (99%) rename {internal/cloud => cloud}/backend_taskStages_test.go (100%) rename {internal/cloud => cloud}/backend_test.go (99%) rename {internal/cloud => cloud}/cloud_integration.go (98%) rename {internal/cloud => cloud}/cloud_variables.go (88%) rename {internal/cloud => cloud}/cloud_variables_test.go (97%) rename {internal/cloud => cloud}/configchangemode_string.go (100%) rename {internal/cloud => cloud}/e2e/README.md (100%) rename {internal/cloud => cloud}/e2e/apply_auto_approve_test.go (100%) rename {internal/cloud => cloud}/e2e/apply_no_input_flag_test.go (100%) rename {internal/cloud => cloud}/e2e/backend_apply_before_init_test.go (100%) rename {internal/cloud => cloud}/e2e/env_variables_test.go (100%) rename {internal/cloud => cloud}/e2e/helper_test.go (100%) rename {internal/cloud => cloud}/e2e/init_with_empty_tags_test.go (100%) rename {internal/cloud => cloud}/e2e/main_test.go (99%) rename {internal/cloud => cloud}/e2e/migrate_state_multi_to_tfc_test.go (100%) rename {internal/cloud => cloud}/e2e/migrate_state_remote_backend_to_tfc_test.go (100%) rename {internal/cloud => cloud}/e2e/migrate_state_single_to_tfc_test.go (100%) rename {internal/cloud => cloud}/e2e/migrate_state_tfc_to_other_test.go (100%) rename {internal/cloud => cloud}/e2e/migrate_state_tfc_to_tfc_test.go (100%) rename {internal/cloud => cloud}/e2e/run_variables_test.go (100%) rename {internal/cloud => cloud}/errors.go (97%) rename {internal/cloud => cloud}/migration.go (97%) rename {internal/cloud => cloud}/migration_test.go (96%) rename {internal/cloud => cloud}/remote_test.go (88%) rename {internal/cloud => cloud}/state.go (97%) rename {internal/cloud => cloud}/state_test.go (98%) rename {internal/cloud => cloud}/testdata/.gitignore (100%) rename {internal/cloud => cloud}/testdata/apply-destroy/apply.log (100%) rename {internal/cloud => cloud}/testdata/apply-destroy/main.tf (100%) rename {internal/cloud => cloud}/testdata/apply-destroy/plan.log (100%) rename {internal/cloud => cloud}/testdata/apply-json-with-error/main.tf (100%) rename {internal/cloud => cloud}/testdata/apply-json-with-error/plan-redacted.json (100%) rename {internal/cloud => cloud}/testdata/apply-json-with-error/plan.log (100%) rename {internal/cloud => cloud}/testdata/apply-json-with-outputs/apply.log (100%) rename {internal/cloud => cloud}/testdata/apply-json-with-outputs/main.tf (100%) rename {internal/cloud => cloud}/testdata/apply-json-with-outputs/plan-redacted.json (100%) rename {internal/cloud => cloud}/testdata/apply-json-with-outputs/plan.log (100%) rename {internal/cloud => cloud}/testdata/apply-json-with-provisioner-error/apply.log (100%) rename {internal/cloud => cloud}/testdata/apply-json-with-provisioner-error/main.tf (100%) rename {internal/cloud => cloud}/testdata/apply-json-with-provisioner-error/plan-redacted.json (100%) rename {internal/cloud => cloud}/testdata/apply-json-with-provisioner-error/plan.log (100%) rename {internal/cloud => cloud}/testdata/apply-json-with-provisioner/apply.log (100%) rename {internal/cloud => cloud}/testdata/apply-json-with-provisioner/main.tf (100%) rename {internal/cloud => cloud}/testdata/apply-json-with-provisioner/plan-redacted.json (100%) rename {internal/cloud => cloud}/testdata/apply-json-with-provisioner/plan.log (100%) rename {internal/cloud => cloud}/testdata/apply-json/apply.log (100%) rename {internal/cloud => cloud}/testdata/apply-json/main.tf (100%) rename {internal/cloud => cloud}/testdata/apply-json/plan-redacted.json (100%) rename {internal/cloud => cloud}/testdata/apply-json/plan.log (100%) rename {internal/cloud => cloud}/testdata/apply-no-changes/main.tf (100%) rename {internal/cloud => cloud}/testdata/apply-no-changes/plan.log (100%) rename {internal/cloud => cloud}/testdata/apply-no-changes/policy.log (100%) rename {internal/cloud => cloud}/testdata/apply-policy-hard-failed/main.tf (100%) rename {internal/cloud => cloud}/testdata/apply-policy-hard-failed/plan.log (100%) rename {internal/cloud => cloud}/testdata/apply-policy-hard-failed/policy.log (100%) rename {internal/cloud => cloud}/testdata/apply-policy-passed/apply.log (100%) rename {internal/cloud => cloud}/testdata/apply-policy-passed/main.tf (100%) rename {internal/cloud => cloud}/testdata/apply-policy-passed/plan.log (100%) rename {internal/cloud => cloud}/testdata/apply-policy-passed/policy.log (100%) rename {internal/cloud => cloud}/testdata/apply-policy-soft-failed/apply.log (100%) rename {internal/cloud => cloud}/testdata/apply-policy-soft-failed/main.tf (100%) rename {internal/cloud => cloud}/testdata/apply-policy-soft-failed/plan.log (100%) rename {internal/cloud => cloud}/testdata/apply-policy-soft-failed/policy.log (100%) rename {internal/cloud => cloud}/testdata/apply-variables/apply.log (100%) rename {internal/cloud => cloud}/testdata/apply-variables/main.tf (100%) rename {internal/cloud => cloud}/testdata/apply-variables/plan.log (100%) rename {internal/cloud => cloud}/testdata/apply-with-error/main.tf (100%) rename {internal/cloud => cloud}/testdata/apply-with-error/plan.log (100%) rename {internal/cloud => cloud}/testdata/apply/apply.log (100%) rename {internal/cloud => cloud}/testdata/apply/main.tf (100%) rename {internal/cloud => cloud}/testdata/apply/plan.log (100%) rename {internal/cloud => cloud}/testdata/empty/.gitignore (100%) rename {internal/cloud => cloud}/testdata/plan-cost-estimation/ce.log (100%) rename {internal/cloud => cloud}/testdata/plan-cost-estimation/cost-estimate.log (100%) rename {internal/cloud => cloud}/testdata/plan-cost-estimation/main.tf (100%) rename {internal/cloud => cloud}/testdata/plan-cost-estimation/plan.log (100%) rename {internal/cloud => cloud}/testdata/plan-json-basic/main.tf (100%) rename {internal/cloud => cloud}/testdata/plan-json-basic/plan-redacted.json (100%) rename {internal/cloud => cloud}/testdata/plan-json-basic/plan.log (100%) rename {internal/cloud => cloud}/testdata/plan-json-error/main.tf (100%) rename {internal/cloud => cloud}/testdata/plan-json-error/plan-redacted.json (100%) rename {internal/cloud => cloud}/testdata/plan-json-error/plan.log (100%) rename {internal/cloud => cloud}/testdata/plan-json-full/main.tf (100%) rename {internal/cloud => cloud}/testdata/plan-json-full/plan-redacted.json (100%) rename {internal/cloud => cloud}/testdata/plan-json-full/plan.log (100%) rename {internal/cloud => cloud}/testdata/plan-long-line/main.tf (100%) rename {internal/cloud => cloud}/testdata/plan-long-line/plan.log (100%) rename {internal/cloud => cloud}/testdata/plan-no-changes/main.tf (100%) rename {internal/cloud => cloud}/testdata/plan-no-changes/plan.log (100%) rename {internal/cloud => cloud}/testdata/plan-no-changes/policy.log (100%) rename {internal/cloud => cloud}/testdata/plan-policy-hard-failed/main.tf (100%) rename {internal/cloud => cloud}/testdata/plan-policy-hard-failed/plan.log (100%) rename {internal/cloud => cloud}/testdata/plan-policy-hard-failed/policy.log (100%) rename {internal/cloud => cloud}/testdata/plan-policy-passed/main.tf (100%) rename {internal/cloud => cloud}/testdata/plan-policy-passed/plan.log (100%) rename {internal/cloud => cloud}/testdata/plan-policy-passed/policy.log (100%) rename {internal/cloud => cloud}/testdata/plan-policy-soft-failed/main.tf (100%) rename {internal/cloud => cloud}/testdata/plan-policy-soft-failed/plan.log (100%) rename {internal/cloud => cloud}/testdata/plan-policy-soft-failed/policy.log (100%) rename {internal/cloud => cloud}/testdata/plan-variables/main.tf (100%) rename {internal/cloud => cloud}/testdata/plan-variables/plan.log (100%) rename {internal/cloud => cloud}/testdata/plan-with-error/main.tf (100%) rename {internal/cloud => cloud}/testdata/plan-with-error/plan.log (100%) rename {internal/cloud => cloud}/testdata/plan-with-working-directory/terraform/main.tf (100%) rename {internal/cloud => cloud}/testdata/plan-with-working-directory/terraform/plan.log (100%) rename {internal/cloud => cloud}/testdata/plan/main.tf (100%) rename {internal/cloud => cloud}/testdata/plan/plan.log (100%) rename {internal/cloud => cloud}/testdata/refresh/main.tf (100%) rename {internal/cloud => cloud}/testdata/variables/main.tf (100%) rename {internal/cloud => cloud}/testing.go (96%) rename {internal/cloud => cloud}/tfe_client_mock.go (99%) rename {internal/command => command}/apply.go (97%) rename {internal/command => command}/apply_destroy_test.go (98%) rename {internal/command => command}/apply_test.go (99%) rename {internal/command => command}/arguments/apply.go (97%) rename {internal/command => command}/arguments/apply_test.go (99%) rename {internal/command => command}/arguments/default.go (100%) rename {internal/command => command}/arguments/extended.go (98%) rename {internal/command => command}/arguments/flags.go (100%) rename {internal/command => command}/arguments/output.go (97%) rename {internal/command => command}/arguments/output_test.go (98%) rename {internal/command => command}/arguments/plan.go (97%) rename {internal/command => command}/arguments/plan_test.go (98%) rename {internal/command => command}/arguments/refresh.go (97%) rename {internal/command => command}/arguments/refresh_test.go (98%) rename {internal/command => command}/arguments/show.go (96%) rename {internal/command => command}/arguments/show_test.go (97%) rename {internal/command => command}/arguments/test.go (97%) rename {internal/command => command}/arguments/test_test.go (96%) rename {internal/command => command}/arguments/types.go (100%) rename {internal/command => command}/arguments/validate.go (96%) rename {internal/command => command}/arguments/validate_test.go (97%) rename {internal/command => command}/arguments/view.go (100%) rename {internal/command => command}/arguments/view_test.go (100%) rename {internal/command => command}/autocomplete.go (100%) rename {internal/command => command}/autocomplete_test.go (100%) rename {internal/command => command}/cli_ui.go (100%) rename {internal/command => command}/cli_ui_test.go (100%) rename {internal/command => command}/cliconfig/cliconfig.go (99%) rename {internal/command => command}/cliconfig/cliconfig_test.go (99%) rename {internal/command => command}/cliconfig/config_unix.go (100%) rename {internal/command => command}/cliconfig/config_windows.go (100%) rename {internal/command => command}/cliconfig/credentials.go (99%) rename {internal/command => command}/cliconfig/credentials_test.go (100%) rename {internal/command => command}/cliconfig/provider_installation.go (98%) rename {internal/command => command}/cliconfig/provider_installation_test.go (96%) rename {internal/command => command}/cliconfig/testdata/config (100%) rename {internal/command => command}/cliconfig/testdata/config-env (100%) rename {internal/command => command}/cliconfig/testdata/credentials (100%) rename {internal/command => command}/cliconfig/testdata/hosts (100%) rename {internal/command => command}/cliconfig/testdata/provider-installation (100%) rename {internal/command => command}/cliconfig/testdata/provider-installation-errors (100%) rename {internal/command => command}/cliconfig/testdata/provider-installation.json (100%) rename {internal/command => command}/clistate/local_state.go (98%) rename {internal/command => command}/clistate/local_state_lock_unix.go (100%) rename {internal/command => command}/clistate/local_state_lock_windows.go (100%) rename {internal/command => command}/clistate/state.go (95%) rename {internal/command => command}/clistate/state_test.go (63%) rename {internal/command => command}/command.go (100%) rename {internal/command => command}/command_test.go (96%) rename {internal/command => command}/console.go (94%) rename {internal/command => command}/console_interactive.go (95%) rename {internal/command => command}/console_interactive_solaris.go (89%) rename {internal/command => command}/console_test.go (98%) rename {internal/command => command}/e2etest/.gitignore (100%) rename {internal/command => command}/e2etest/automation_test.go (98%) rename {internal/command => command}/e2etest/doc.go (94%) rename {internal/command => command}/e2etest/init_test.go (99%) rename {internal/command => command}/e2etest/main_test.go (97%) rename {internal/command => command}/e2etest/make-archive.sh (100%) rename {internal/command => command}/e2etest/module_archive_test.go (93%) rename {internal/command => command}/e2etest/primary_test.go (98%) rename {internal/command => command}/e2etest/provider_dev_test.go (96%) rename {internal/command => command}/e2etest/provider_plugin_test.go (93%) rename {internal/command => command}/e2etest/providers_mirror_test.go (98%) rename {internal/command => command}/e2etest/providers_tamper_test.go (98%) rename {internal/command => command}/e2etest/provisioner_plugin_test.go (92%) rename {internal/command => command}/e2etest/provisioner_test.go (95%) rename {internal/command => command}/e2etest/remote_state_test.go (92%) rename {internal/command => command}/e2etest/strip_ansi.go (100%) rename {internal/command => command}/e2etest/terraform_test.go (93%) rename {internal/command => command}/e2etest/testdata/chdir-option/subdir/main.tf (100%) rename {internal/command => command}/e2etest/testdata/custom-provider-install-method/cliconfig.tfrc (100%) rename {internal/command => command}/e2etest/testdata/custom-provider-install-method/cliconfig.tfrc.json (100%) rename {internal/command => command}/e2etest/testdata/custom-provider-install-method/fs-mirror/example.com/awesomecorp/happycloud/1.2.0/os_arch/terraform-provider-happycloud_v1.2.0 (100%) rename {internal/command => command}/e2etest/testdata/custom-provider-install-method/main.tf (100%) rename {internal/command => command}/e2etest/testdata/empty/.exists (100%) rename {internal/command => command}/e2etest/testdata/full-workflow-null/main.tf (100%) rename {internal/command => command}/e2etest/testdata/local-only-provider/main.tf (100%) rename {internal/command => command}/e2etest/testdata/local-only-provider/terraform.d/plugins/example.com/awesomecorp/happycloud/1.2.0/os_arch/terraform-provider-happycloud_v1.2.0 (100%) rename {internal/command => command}/e2etest/testdata/module-archive/main.tf (100%) rename {internal/command => command}/e2etest/testdata/plugin-cache/.terraform.lock.hcl (100%) rename {internal/command => command}/e2etest/testdata/plugin-cache/cache/registry.terraform.io/hashicorp/template/2.1.0/os_arch/terraform-provider-template_v2.1.0_x4 (100%) rename {internal/command => command}/e2etest/testdata/plugin-cache/main.tf (100%) rename {internal/command => command}/e2etest/testdata/provider-dev-override/pkgdir/.exists (100%) rename {internal/command => command}/e2etest/testdata/provider-dev-override/provider-dev-override.tf (100%) rename {internal/command => command}/e2etest/testdata/provider-not-found-non-default/main.tf (100%) rename {internal/command => command}/e2etest/testdata/provider-not-found/main.tf (100%) rename {internal/command => command}/e2etest/testdata/provider-plugin/main.tf (100%) rename {internal/command => command}/e2etest/testdata/provider-tampering-base/provider-tampering-base.tf (100%) rename {internal/command => command}/e2etest/testdata/provider-warnings/main.tf (100%) rename {internal/command => command}/e2etest/testdata/provisioner-plugin/main.tf (100%) rename {internal/command => command}/e2etest/testdata/provisioner/main.tf (100%) rename {internal/command => command}/e2etest/testdata/template-provider/main.tf (100%) rename {internal/command => command}/e2etest/testdata/terraform-managed-data/main.tf (100%) rename {internal/command => command}/e2etest/testdata/terraform-provider/main.tf (100%) rename {internal/command => command}/e2etest/testdata/terraform-provider/test.tfstate (100%) rename {internal/command => command}/e2etest/testdata/terraform-providers-mirror-with-lock-file/.terraform.lock.hcl (100%) rename {internal/command => command}/e2etest/testdata/terraform-providers-mirror-with-lock-file/terraform-providers-mirror.tf (100%) rename {internal/command => command}/e2etest/testdata/terraform-providers-mirror/terraform-providers-mirror.tf (100%) rename {internal/command => command}/e2etest/testdata/test-provider/main.tf (100%) rename {internal/command => command}/e2etest/testdata/vendored-provider/main.tf (100%) rename {internal/command => command}/e2etest/testdata/vendored-provider/terraform.d/plugins/registry.terraform.io/hashicorp/null/1.0.0+local/os_arch/terraform-provider-null_v1.0.0 (100%) rename {internal/command => command}/e2etest/unmanaged_test.go (94%) rename {internal/command => command}/e2etest/version_test.go (98%) rename {internal/command => command}/flag_kv.go (100%) rename {internal/command => command}/flag_kv_test.go (100%) rename {internal/command => command}/fmt.go (99%) rename {internal/command => command}/fmt_test.go (100%) rename {internal/command => command}/format/diagnostic.go (98%) rename {internal/command => command}/format/diagnostic_test.go (99%) rename {internal/command => command}/format/diff.go (99%) rename {internal/command => command}/format/diff_test.go (99%) rename {internal/command => command}/format/difflanguage_string.go (100%) rename {internal/command => command}/format/format.go (100%) rename {internal/command => command}/format/object_id.go (98%) rename {internal/command => command}/format/object_id_test.go (98%) rename {internal/command => command}/format/state.go (95%) rename {internal/command => command}/format/state_test.go (97%) rename {internal/command => command}/format/trivia.go (100%) rename {internal/command => command}/get.go (97%) rename {internal/command => command}/get_test.go (100%) rename {internal/command => command}/graph.go (94%) rename {internal/command => command}/graph_test.go (96%) rename {internal/command => command}/helper.go (87%) rename {internal/command => command}/hook_module_install.go (94%) rename {internal/command => command}/import.go (96%) rename {internal/command => command}/import_test.go (99%) rename {internal/command => command}/init.go (98%) rename {internal/command => command}/init_test.go (99%) rename {internal/command => command}/jsonchecks/checks.go (98%) rename {internal/command => command}/jsonchecks/checks_test.go (97%) rename {internal/command => command}/jsonchecks/doc.go (100%) rename {internal/command => command}/jsonchecks/objects.go (97%) rename {internal/command => command}/jsonchecks/status.go (91%) rename {internal/command => command}/jsonconfig/config.go (98%) rename {internal/command => command}/jsonconfig/config_test.go (100%) rename {internal/command => command}/jsonconfig/doc.go (100%) rename {internal/command => command}/jsonconfig/expression.go (96%) rename {internal/command => command}/jsonconfig/expression_test.go (97%) rename {internal/command => command}/jsonformat/README.md (100%) rename {internal/command => command}/jsonformat/collections/action.go (85%) rename {internal/command => command}/jsonformat/collections/map.go (82%) rename {internal/command => command}/jsonformat/collections/slice.go (92%) rename {internal/command => command}/jsonformat/computed/diff.go (98%) rename {internal/command => command}/jsonformat/computed/doc.go (100%) rename {internal/command => command}/jsonformat/computed/renderers/block.go (98%) rename {internal/command => command}/jsonformat/computed/renderers/blocks.go (97%) rename {internal/command => command}/jsonformat/computed/renderers/json.go (88%) rename {internal/command => command}/jsonformat/computed/renderers/list.go (97%) rename {internal/command => command}/jsonformat/computed/renderers/map.go (96%) rename {internal/command => command}/jsonformat/computed/renderers/object.go (96%) rename {internal/command => command}/jsonformat/computed/renderers/primitive.go (96%) rename {internal/command => command}/jsonformat/computed/renderers/renderer_test.go (99%) rename {internal/command => command}/jsonformat/computed/renderers/sensitive.go (93%) rename {internal/command => command}/jsonformat/computed/renderers/sensitive_block.go (93%) rename {internal/command => command}/jsonformat/computed/renderers/set.go (95%) rename {internal/command => command}/jsonformat/computed/renderers/string.go (92%) rename {internal/command => command}/jsonformat/computed/renderers/testing.go (98%) rename {internal/command => command}/jsonformat/computed/renderers/type_change.go (90%) rename {internal/command => command}/jsonformat/computed/renderers/unknown.go (86%) rename {internal/command => command}/jsonformat/computed/renderers/util.go (94%) rename {internal/command => command}/jsonformat/diff.go (84%) rename {internal/command => command}/jsonformat/differ/attribute.go (93%) rename {internal/command => command}/jsonformat/differ/block.go (90%) rename {internal/command => command}/jsonformat/differ/differ.go (70%) rename {internal/command => command}/jsonformat/differ/differ_test.go (99%) rename {internal/command => command}/jsonformat/differ/list.go (86%) rename {internal/command => command}/jsonformat/differ/map.go (81%) rename {internal/command => command}/jsonformat/differ/object.go (86%) rename {internal/command => command}/jsonformat/differ/output.go (64%) rename {internal/command => command}/jsonformat/differ/primitive.go (51%) rename {internal/command => command}/jsonformat/differ/sensitive.go (82%) rename {internal/command => command}/jsonformat/differ/set.go (90%) rename {internal/command => command}/jsonformat/differ/tuple.go (71%) rename {internal/command => command}/jsonformat/differ/types.go (100%) rename {internal/command => command}/jsonformat/differ/unknown.go (86%) rename {internal/command => command}/jsonformat/jsondiff/diff.go (94%) rename {internal/command => command}/jsonformat/jsondiff/types.go (100%) rename {internal/command => command}/jsonformat/plan.go (97%) rename {internal/command => command}/jsonformat/plan_test.go (99%) rename {internal/command => command}/jsonformat/renderer.go (89%) rename {internal/command => command}/jsonformat/state.go (90%) rename {internal/command => command}/jsonformat/state_test.go (94%) rename {internal/command => command}/jsonformat/structured/attribute_path/matcher.go (100%) rename {internal/command => command}/jsonformat/structured/attribute_path/matcher_test.go (100%) rename {internal/command => command}/jsonformat/structured/change.go (96%) rename {internal/command => command}/jsonformat/structured/doc.go (100%) rename {internal/command => command}/jsonformat/structured/map.go (98%) rename {internal/command => command}/jsonformat/structured/sensitive.go (96%) rename {internal/command => command}/jsonformat/structured/slice.go (97%) rename {internal/command => command}/jsonformat/structured/unknown.go (97%) rename {internal/command => command}/jsonfunction/function.go (98%) rename {internal/command => command}/jsonfunction/function_test.go (100%) rename {internal/command => command}/jsonfunction/parameter.go (100%) rename {internal/command => command}/jsonfunction/parameter_test.go (100%) rename {internal/command => command}/jsonfunction/return_type.go (100%) rename {internal/command => command}/jsonplan/doc.go (100%) rename {internal/command => command}/jsonplan/module.go (100%) rename {internal/command => command}/jsonplan/plan.go (98%) rename {internal/command => command}/jsonplan/plan_test.go (99%) rename {internal/command => command}/jsonplan/resource.go (98%) rename {internal/command => command}/jsonplan/values.go (96%) rename {internal/command => command}/jsonplan/values_test.go (97%) rename {internal/command => command}/jsonprovider/attribute.go (96%) rename {internal/command => command}/jsonprovider/attribute_test.go (93%) rename {internal/command => command}/jsonprovider/block.go (97%) rename {internal/command => command}/jsonprovider/block_test.go (96%) rename {internal/command => command}/jsonprovider/doc.go (100%) rename {internal/command => command}/jsonprovider/provider.go (97%) rename {internal/command => command}/jsonprovider/provider_test.go (97%) rename {internal/command => command}/jsonprovider/schema.go (92%) rename {internal/command => command}/jsonprovider/schema_test.go (92%) rename {internal/command => command}/jsonstate/doc.go (100%) rename {internal/command => command}/jsonstate/state.go (97%) rename {internal/command => command}/jsonstate/state_test.go (98%) rename {internal/command => command}/login.go (99%) rename {internal/command => command}/login_test.go (96%) rename {internal/command => command}/logout.go (97%) rename {internal/command => command}/logout_test.go (97%) rename {internal/command => command}/meta.go (96%) rename {internal/command => command}/meta_backend.go (98%) rename {internal/command => command}/meta_backend_migrate.go (98%) rename {internal/command => command}/meta_backend_migrate_test.go (100%) rename {internal/command => command}/meta_backend_test.go (98%) rename {internal/command => command}/meta_config.go (97%) rename {internal/command => command}/meta_dependencies.go (97%) rename {internal/command => command}/meta_new.go (94%) rename {internal/command => command}/meta_providers.go (97%) rename {internal/command => command}/meta_test.go (98%) rename {internal/command => command}/meta_vars.go (97%) rename {internal/command => command}/metadata_command.go (100%) rename {internal/command => command}/metadata_functions.go (94%) rename {internal/command => command}/metadata_functions_test.go (100%) rename {internal/command => command}/output.go (92%) rename {internal/command => command}/output_test.go (98%) rename {internal/command => command}/plan.go (97%) rename {internal/command => command}/plan_test.go (98%) rename {internal/command => command}/plugins.go (91%) rename {internal/command => command}/plugins_lock.go (100%) rename {internal/command => command}/plugins_lock_test.go (100%) rename {internal/command => command}/plugins_test.go (100%) rename {internal/command => command}/providers.go (96%) rename {internal/command => command}/providers_lock.go (98%) rename {internal/command => command}/providers_lock_test.go (97%) rename {internal/command => command}/providers_mirror.go (98%) rename {internal/command => command}/providers_mirror_test.go (100%) rename {internal/command => command}/providers_schema.go (92%) rename {internal/command => command}/providers_schema_test.go (95%) rename {internal/command => command}/providers_test.go (100%) rename {internal/command => command}/push.go (95%) rename {internal/command => command}/refresh.go (96%) rename {internal/command => command}/refresh_test.go (98%) rename {internal/command => command}/show.go (92%) rename {internal/command => command}/show_test.go (98%) rename {internal/command => command}/state_command.go (100%) rename {internal/command => command}/state_list.go (96%) rename {internal/command => command}/state_list_test.go (100%) rename {internal/command => command}/state_meta.go (95%) rename {internal/command => command}/state_mv.go (97%) rename {internal/command => command}/state_mv_test.go (99%) rename {internal/command => command}/state_pull.go (94%) rename {internal/command => command}/state_pull_test.go (100%) rename {internal/command => command}/state_push.go (92%) rename {internal/command => command}/state_push_test.go (97%) rename {internal/command => command}/state_replace_provider.go (94%) rename {internal/command => command}/state_replace_provider_test.go (99%) rename {internal/command => command}/state_rm.go (94%) rename {internal/command => command}/state_rm_test.go (99%) rename {internal/command => command}/state_show.go (94%) rename {internal/command => command}/state_show_test.go (96%) rename {internal/command => command}/state_test.go (93%) rename {internal/command => command}/taint.go (95%) rename {internal/command => command}/taint_test.go (99%) rename {internal/command => command}/test.go (97%) rename {internal/command => command}/test_test.go (97%) rename {internal/command => command}/testdata/apply-config-invalid/main.tf (100%) rename {internal/command => command}/testdata/apply-destroy-targeted/main.tf (100%) rename {internal/command => command}/testdata/apply-error/main.tf (100%) rename {internal/command => command}/testdata/apply-input-partial/main.tf (100%) rename {internal/command => command}/testdata/apply-input/main.tf (100%) rename {internal/command => command}/testdata/apply-plan-no-module/main.tf (100%) rename {internal/command => command}/testdata/apply-replace/main.tf (100%) rename {internal/command => command}/testdata/apply-sensitive-output/main.tf (100%) rename {internal/command => command}/testdata/apply-shutdown/main.tf (100%) rename {internal/command => command}/testdata/apply-targeted/main.tf (100%) rename {internal/command => command}/testdata/apply-terraform-env/main.tf (100%) rename {internal/command => command}/testdata/apply-vars/main.tf (100%) rename {internal/command => command}/testdata/apply/main.tf (100%) rename {internal/command => command}/testdata/apply/output.jsonlog (100%) rename {internal/command => command}/testdata/backend-change-multi-default-to-single/.terraform/terraform.tfstate (100%) rename {internal/command => command}/testdata/backend-change-multi-default-to-single/local-state.tfstate (100%) rename {internal/command => command}/testdata/backend-change-multi-default-to-single/main.tf (100%) rename {internal/command => command}/testdata/backend-change-multi-to-multi/.terraform/terraform.tfstate (100%) rename {internal/command => command}/testdata/backend-change-multi-to-multi/local-state.tfstate (100%) rename {internal/command => command}/testdata/backend-change-multi-to-multi/main.tf (100%) rename {internal/command => command}/testdata/backend-change-multi-to-multi/terraform.tfstate.d/env2/terraform.tfstate (100%) rename {internal/command => command}/testdata/backend-change-multi-to-no-default-with-default/.terraform/terraform.tfstate (100%) rename {internal/command => command}/testdata/backend-change-multi-to-no-default-with-default/local-state.tfstate (100%) rename {internal/command => command}/testdata/backend-change-multi-to-no-default-with-default/main.tf (100%) rename {internal/command => command}/testdata/backend-change-multi-to-no-default-with-default/terraform.tfstate.d/env2/terraform.tfstate (100%) rename {internal/command => command}/testdata/backend-change-multi-to-no-default-without-default/.terraform/terraform.tfstate (100%) rename {internal/command => command}/testdata/backend-change-multi-to-no-default-without-default/main.tf (100%) rename {internal/command => command}/testdata/backend-change-multi-to-no-default-without-default/terraform.tfstate.d/env2/terraform.tfstate (100%) rename {internal/command => command}/testdata/backend-change-multi-to-single/.terraform/environment (100%) rename {internal/command => command}/testdata/backend-change-multi-to-single/.terraform/terraform.tfstate (100%) rename {internal/command => command}/testdata/backend-change-multi-to-single/main.tf (100%) rename {internal/command => command}/testdata/backend-change-multi-to-single/terraform.tfstate.d/env1/terraform.tfstate (100%) rename {internal/command => command}/testdata/backend-change-multi-to-single/terraform.tfstate.d/env2/terraform.tfstate (100%) rename {internal/command => command}/testdata/backend-change-single-to-single/.terraform/terraform.tfstate (100%) rename {internal/command => command}/testdata/backend-change-single-to-single/local-state.tfstate (100%) rename {internal/command => command}/testdata/backend-change-single-to-single/main.tf (100%) rename {internal/command => command}/testdata/backend-change/.terraform/terraform.tfstate (100%) rename {internal/command => command}/testdata/backend-change/local-state.tfstate (100%) rename {internal/command => command}/testdata/backend-change/main.tf (100%) rename {internal/command => command}/testdata/backend-changed-with-legacy/.terraform/terraform.tfstate (100%) rename {internal/command => command}/testdata/backend-changed-with-legacy/local-state-old.tfstate (100%) rename {internal/command => command}/testdata/backend-changed-with-legacy/local-state.tfstate (100%) rename {internal/command => command}/testdata/backend-changed-with-legacy/main.tf (100%) rename {internal/command => command}/testdata/backend-from-state/terraform.tfstate (100%) rename {internal/command => command}/testdata/backend-inmem-locked/main.tf (100%) rename {internal/command => command}/testdata/backend-new-interp/main.tf (100%) rename {internal/command => command}/testdata/backend-new-legacy/.terraform/terraform.tfstate (100%) rename {internal/command => command}/testdata/backend-new-legacy/local-state-old.tfstate (100%) rename {internal/command => command}/testdata/backend-new-legacy/main.tf (100%) rename {internal/command => command}/testdata/backend-new-migrate-existing/local-state.tfstate (100%) rename {internal/command => command}/testdata/backend-new-migrate-existing/main.tf (100%) rename {internal/command => command}/testdata/backend-new-migrate-existing/terraform.tfstate (100%) rename {internal/command => command}/testdata/backend-new-migrate/main.tf (100%) rename {internal/command => command}/testdata/backend-new-migrate/terraform.tfstate (100%) rename {internal/command => command}/testdata/backend-new/main.tf (100%) rename {internal/command => command}/testdata/backend-plan-backend-empty-config/.terraform/terraform.tfstate (100%) rename {internal/command => command}/testdata/backend-plan-backend-empty-config/local-state.tfstate (100%) rename {internal/command => command}/testdata/backend-plan-backend-empty-config/main.tf (100%) rename {internal/command => command}/testdata/backend-plan-backend-empty/readme.txt (100%) rename {internal/command => command}/testdata/backend-plan-backend-match/local-state.tfstate (100%) rename {internal/command => command}/testdata/backend-plan-backend-match/readme.txt (100%) rename {internal/command => command}/testdata/backend-plan-backend-mismatch/local-state.tfstate (100%) rename {internal/command => command}/testdata/backend-plan-legacy-data/local-state.tfstate (100%) rename {internal/command => command}/testdata/backend-plan-legacy-data/main.tf (100%) rename {internal/command => command}/testdata/backend-plan-legacy-data/state.tfstate (100%) rename {internal/command => command}/testdata/backend-plan-legacy/readme.txt (100%) rename {internal/command => command}/testdata/backend-plan-local-match/main.tf (100%) rename {internal/command => command}/testdata/backend-plan-local-match/terraform.tfstate (100%) rename {internal/command => command}/testdata/backend-plan-local-mismatch-lineage/main.tf (100%) rename {internal/command => command}/testdata/backend-plan-local-mismatch-lineage/terraform.tfstate (100%) rename {internal/command => command}/testdata/backend-plan-local-newer/main.tf (100%) rename {internal/command => command}/testdata/backend-plan-local-newer/terraform.tfstate (100%) rename {internal/command => command}/testdata/backend-plan-local/main.tf (100%) rename {internal/command => command}/testdata/backend-unchanged-with-legacy/.terraform/terraform.tfstate (100%) rename {internal/command => command}/testdata/backend-unchanged-with-legacy/local-state-old.tfstate (100%) rename {internal/command => command}/testdata/backend-unchanged-with-legacy/local-state.tfstate (100%) rename {internal/command => command}/testdata/backend-unchanged-with-legacy/main.tf (100%) rename {internal/command => command}/testdata/backend-unchanged/.terraform/terraform.tfstate (100%) rename {internal/command => command}/testdata/backend-unchanged/local-state.tfstate (100%) rename {internal/command => command}/testdata/backend-unchanged/main.tf (100%) rename {internal/command => command}/testdata/backend-unset-with-legacy/.terraform/terraform.tfstate (100%) rename {internal/command => command}/testdata/backend-unset-with-legacy/local-state-old.tfstate (100%) rename {internal/command => command}/testdata/backend-unset-with-legacy/local-state.tfstate (100%) rename {internal/command => command}/testdata/backend-unset-with-legacy/main.tf (100%) rename {internal/command => command}/testdata/backend-unset/.terraform/terraform.tfstate (100%) rename {internal/command => command}/testdata/backend-unset/local-state.tfstate (100%) rename {internal/command => command}/testdata/backend-unset/main.tf (100%) rename {internal/command => command}/testdata/command-check-required-version/main.tf (100%) rename {internal/command => command}/testdata/empty-file (100%) rename {internal/command => command}/testdata/empty/README (100%) rename {internal/command => command}/testdata/fmt/general_in.tf (100%) rename {internal/command => command}/testdata/fmt/general_out.tf (100%) rename {internal/command => command}/testdata/fmt/variable_type_in.tf (100%) rename {internal/command => command}/testdata/fmt/variable_type_out.tf (100%) rename {internal/command => command}/testdata/get/foo/main.tf (100%) rename {internal/command => command}/testdata/get/main.tf (100%) rename {internal/command => command}/testdata/graph/main.tf (100%) rename {internal/command => command}/testdata/import-missing-resource-config/main.tf (100%) rename {internal/command => command}/testdata/import-module-input-variable/child/main.tf (100%) rename {internal/command => command}/testdata/import-module-input-variable/main.tf (100%) rename {internal/command => command}/testdata/import-module-input-variable/terraform.tfvars (100%) rename {internal/command => command}/testdata/import-module-var-file/child/main.tf (100%) rename {internal/command => command}/testdata/import-module-var-file/main.tf (100%) rename {internal/command => command}/testdata/import-module-var-file/terraform.tfvars (100%) rename {internal/command => command}/testdata/import-provider-aliased/main.tf (100%) rename {internal/command => command}/testdata/import-provider-datasource/main.tf (100%) rename {internal/command => command}/testdata/import-provider-implicit/main.tf (100%) rename {internal/command => command}/testdata/import-provider-invalid/main.tf (100%) rename {internal/command => command}/testdata/import-provider-remote-state/main.tf (100%) rename {internal/command => command}/testdata/import-provider-var-default/main.tf (100%) rename {internal/command => command}/testdata/import-provider-var-default/terraform.tfvars (100%) rename {internal/command => command}/testdata/import-provider-var-file/blah.tfvars (100%) rename {internal/command => command}/testdata/import-provider-var-file/main.tf (100%) rename {internal/command => command}/testdata/import-provider-var/main.tf (100%) rename {internal/command => command}/testdata/import-provider/main.tf (100%) rename {internal/command => command}/testdata/init-backend-config-file-change-migrate-existing/.terraform/terraform.tfstate (100%) rename {internal/command => command}/testdata/init-backend-config-file-change-migrate-existing/input.config (100%) rename {internal/command => command}/testdata/init-backend-config-file-change-migrate-existing/local-state.tfstate (100%) rename {internal/command => command}/testdata/init-backend-config-file-change-migrate-existing/main.tf (100%) rename {internal/command => command}/testdata/init-backend-config-file-change/.terraform/terraform.tfstate (100%) rename {internal/command => command}/testdata/init-backend-config-file-change/input.config (100%) rename {internal/command => command}/testdata/init-backend-config-file-change/main.tf (100%) rename {internal/command => command}/testdata/init-backend-config-file/backend.config (100%) rename {internal/command => command}/testdata/init-backend-config-file/input.config (100%) rename {internal/command => command}/testdata/init-backend-config-file/invalid.config (100%) rename {internal/command => command}/testdata/init-backend-config-file/main.tf (100%) rename {internal/command => command}/testdata/init-backend-config-kv/main.tf (100%) rename {internal/command => command}/testdata/init-backend-empty/main.tf (100%) rename {internal/command => command}/testdata/init-backend-http/main.tf (100%) rename {internal/command => command}/testdata/init-backend-migrate-while-locked/.terraform/terraform.tfstate (100%) rename {internal/command => command}/testdata/init-backend-migrate-while-locked/input.config (100%) rename {internal/command => command}/testdata/init-backend-migrate-while-locked/main.tf (100%) rename {internal/command => command}/testdata/init-backend-selected-workspace-doesnt-exist-multi/.terraform/environment (100%) rename {internal/command => command}/testdata/init-backend-selected-workspace-doesnt-exist-multi/.terraform/terraform.tfstate (100%) rename {internal/command => command}/testdata/init-backend-selected-workspace-doesnt-exist-multi/main.tf (100%) rename {internal/command => command}/testdata/init-backend-selected-workspace-doesnt-exist-multi/terraform.tfstate (100%) rename {internal/command => command}/testdata/init-backend-selected-workspace-doesnt-exist-multi/terraform.tfstate.d/foo/terraform.tfstate (100%) rename {internal/command => command}/testdata/init-backend-selected-workspace-doesnt-exist-single/.terraform/environment (100%) rename {internal/command => command}/testdata/init-backend-selected-workspace-doesnt-exist-single/.terraform/terraform.tfstate (100%) rename {internal/command => command}/testdata/init-backend-selected-workspace-doesnt-exist-single/main.tf (100%) rename {internal/command => command}/testdata/init-backend/main.tf (100%) rename {internal/command => command}/testdata/init-check-required-version-first-module/main.tf (100%) rename {internal/command => command}/testdata/init-check-required-version-first-module/mod/main.tf (100%) rename {internal/command => command}/testdata/init-check-required-version-first/main.tf (100%) rename {internal/command => command}/testdata/init-check-required-version/main.tf (100%) rename {internal/command => command}/testdata/init-cloud-simple/init-cloud-simple.tf (100%) rename {internal/command => command}/testdata/init-get-provider-detected-legacy/.terraform/modules/dicerolls/terraform-random-bar-1.0.0/main.tf (100%) rename {internal/command => command}/testdata/init-get-provider-detected-legacy/.terraform/modules/modules.json (100%) rename {internal/command => command}/testdata/init-get-provider-detected-legacy/child/main.tf (100%) rename {internal/command => command}/testdata/init-get-provider-detected-legacy/main.tf (100%) rename {internal/command => command}/testdata/init-get-provider-invalid-package/main.tf (100%) rename {internal/command => command}/testdata/init-get-provider-legacy-from-state/main.tf (100%) rename {internal/command => command}/testdata/init-get-provider-legacy-from-state/terraform.tfstate (100%) rename {internal/command => command}/testdata/init-get-provider-source/main.tf (100%) rename {internal/command => command}/testdata/init-get-providers/main.tf (100%) rename {internal/command => command}/testdata/init-get/foo/main.tf (100%) rename {internal/command => command}/testdata/init-get/main.tf (100%) rename {internal/command => command}/testdata/init-internal-invalid/main.tf (100%) rename {internal/command => command}/testdata/init-internal/main.tf (100%) rename {internal/command => command}/testdata/init-legacy-provider-cache/.terraform/plugins/example.com/test/b/1.1.0/os_arch/terraform-provider-b (100%) rename {internal/command => command}/testdata/init-legacy-provider-cache/.terraform/plugins/registry.terraform.io/hashicorp/c/2.0.0/os_arch/terraform-provider-c (100%) rename {internal/command => command}/testdata/init-legacy-provider-cache/versions.tf (100%) rename {internal/command => command}/testdata/init-legacy-rc/main.tf (100%) rename {internal/command => command}/testdata/init-provider-lock-file-readonly-add/main.tf (100%) rename {internal/command => command}/testdata/init-provider-lock-file/main.tf (100%) rename {internal/command => command}/testdata/init-provider-now-unused/main.tf (100%) rename {internal/command => command}/testdata/init-providers-lock/main.tf (100%) rename {internal/command => command}/testdata/init-registry-module/main.tf (100%) rename {internal/command => command}/testdata/init-required-providers/main.tf (100%) rename {internal/command => command}/testdata/init-syntax-invalid-backend-invalid/main.tf (100%) rename {internal/command => command}/testdata/init-syntax-invalid-no-backend/main.tf (100%) rename {internal/command => command}/testdata/init-syntax-invalid-with-backend/main.tf (100%) rename {internal/command => command}/testdata/init/hello.tf (100%) rename {internal/command => command}/testdata/inmem-backend/main.tf (100%) rename {internal/command => command}/testdata/login-oauth-server/main.go (88%) rename {internal/command => command}/testdata/login-oauth-server/oauthserver.go (100%) rename {internal/command => command}/testdata/login-tfe-server/tfeserver.go (100%) rename {internal/command => command}/testdata/modules/.terraform/modules/modules.json (100%) rename {internal/command => command}/testdata/modules/child/main.tf (100%) rename {internal/command => command}/testdata/modules/main.tf (100%) rename {internal/command => command}/testdata/modules/terraform.tfstate (100%) rename {internal/command => command}/testdata/parallelism/main.tf (100%) rename {internal/command => command}/testdata/plan-emptydiff/main.tf (100%) rename {internal/command => command}/testdata/plan-fail-condition/main.tf (100%) rename {internal/command => command}/testdata/plan-invalid/main.tf (100%) rename {internal/command => command}/testdata/plan-out-backend-legacy/main.tf (100%) rename {internal/command => command}/testdata/plan-out-backend/main.tf (100%) rename {internal/command => command}/testdata/plan-provider-input/main.tf (100%) rename {internal/command => command}/testdata/plan-replace/main.tf (100%) rename {internal/command => command}/testdata/plan-vars/main.tf (100%) rename {internal/command => command}/testdata/plan/main.tf (100%) rename {internal/command => command}/testdata/plan/output.jsonlog (100%) rename {internal/command => command}/testdata/providers-lock/append/.terraform.lock.hcl (100%) rename {internal/command => command}/testdata/providers-lock/append/fs-mirror/registry.terraform.io/hashicorp/test/1.0.0/os_arch/terraform-provider-test (100%) rename {internal/command => command}/testdata/providers-lock/append/main.tf (100%) rename {internal/command => command}/testdata/providers-lock/basic/fs-mirror/registry.terraform.io/hashicorp/test/1.0.0/os_arch/terraform-provider-test (100%) rename {internal/command => command}/testdata/providers-lock/basic/main.tf (100%) rename {internal/command => command}/testdata/providers-schema/basic/output.json (100%) rename {internal/command => command}/testdata/providers-schema/basic/provider.tf (100%) rename {internal/command => command}/testdata/providers-schema/empty/main.tf (100%) rename {internal/command => command}/testdata/providers-schema/empty/output.json (100%) rename {internal/command => command}/testdata/providers-schema/required/output.json (100%) rename {internal/command => command}/testdata/providers-schema/required/provider.tf (100%) rename {internal/command => command}/testdata/providers/basic/main.tf (100%) rename {internal/command => command}/testdata/providers/modules/child/main.tf (100%) rename {internal/command => command}/testdata/providers/modules/main.tf (100%) rename {internal/command => command}/testdata/providers/state/main.tf (100%) rename {internal/command => command}/testdata/providers/state/terraform.tfstate (100%) rename {internal/command => command}/testdata/push-backend-new/main.tf (100%) rename {internal/command => command}/testdata/push-input-partial/main.tf (100%) rename {internal/command => command}/testdata/push-input/main.tf (100%) rename {internal/command => command}/testdata/push-no-remote/main.tf (100%) rename {internal/command => command}/testdata/push-no-upload/child/main.tf (100%) rename {internal/command => command}/testdata/push-no-upload/main.tf (100%) rename {internal/command => command}/testdata/push-tfvars/main.tf (100%) rename {internal/command => command}/testdata/push-tfvars/terraform.tfvars (100%) rename {internal/command => command}/testdata/push/main.tf (100%) rename {internal/command => command}/testdata/refresh-empty/main.tf (100%) rename {internal/command => command}/testdata/refresh-output/main.tf (100%) rename {internal/command => command}/testdata/refresh-targeted/main.tf (100%) rename {internal/command => command}/testdata/refresh-unset-var/main.tf (100%) rename {internal/command => command}/testdata/refresh-var/main.tf (100%) rename {internal/command => command}/testdata/refresh/main.tf (100%) rename {internal/command => command}/testdata/show-corrupt-statefile/terraform.tfstate (100%) rename {internal/command => command}/testdata/show-json-sensitive/main.tf (100%) rename {internal/command => command}/testdata/show-json-sensitive/output.json (100%) rename {internal/command => command}/testdata/show-json-state/basic/output.json (100%) rename {internal/command => command}/testdata/show-json-state/basic/terraform.tfstate (100%) rename {internal/command => command}/testdata/show-json-state/empty/output.json (100%) rename {internal/command => command}/testdata/show-json-state/empty/terraform.tfstate (100%) rename {internal/command => command}/testdata/show-json-state/modules/bar/main.tf (100%) rename {internal/command => command}/testdata/show-json-state/modules/foo/main.tf (100%) rename {internal/command => command}/testdata/show-json-state/modules/main.tf (100%) rename {internal/command => command}/testdata/show-json-state/modules/output.json (100%) rename {internal/command => command}/testdata/show-json-state/modules/terraform.tfstate (100%) rename {internal/command => command}/testdata/show-json-state/no-state/output.json (100%) rename {internal/command => command}/testdata/show-json-state/sensitive-variables/output.json (100%) rename {internal/command => command}/testdata/show-json-state/sensitive-variables/terraform.tfstate (100%) rename {internal/command => command}/testdata/show-json/basic-create/main.tf (100%) rename {internal/command => command}/testdata/show-json/basic-create/output.json (100%) rename {internal/command => command}/testdata/show-json/basic-delete/main.tf (100%) rename {internal/command => command}/testdata/show-json/basic-delete/output.json (100%) rename {internal/command => command}/testdata/show-json/basic-delete/terraform.tfstate (100%) rename {internal/command => command}/testdata/show-json/basic-update/main.tf (100%) rename {internal/command => command}/testdata/show-json/basic-update/output.json (100%) rename {internal/command => command}/testdata/show-json/basic-update/terraform.tfstate (100%) rename {internal/command => command}/testdata/show-json/conditions/for-refresh.tfstate (100%) rename {internal/command => command}/testdata/show-json/conditions/main.tf (100%) rename {internal/command => command}/testdata/show-json/conditions/output-refresh-only.json (100%) rename {internal/command => command}/testdata/show-json/conditions/output.json (100%) rename {internal/command => command}/testdata/show-json/drift/main.tf (100%) rename {internal/command => command}/testdata/show-json/drift/output.json (100%) rename {internal/command => command}/testdata/show-json/drift/terraform.tfstate (100%) rename {internal/command => command}/testdata/show-json/module-depends-on/foo/main.tf (100%) rename {internal/command => command}/testdata/show-json/module-depends-on/main.tf (100%) rename {internal/command => command}/testdata/show-json/module-depends-on/output.json (100%) rename {internal/command => command}/testdata/show-json/modules/bar/main.tf (100%) rename {internal/command => command}/testdata/show-json/modules/foo/main.tf (100%) rename {internal/command => command}/testdata/show-json/modules/main.tf (100%) rename {internal/command => command}/testdata/show-json/modules/output.json (100%) rename {internal/command => command}/testdata/show-json/moved-drift/main.tf (100%) rename {internal/command => command}/testdata/show-json/moved-drift/output.json (100%) rename {internal/command => command}/testdata/show-json/moved-drift/terraform.tfstate (100%) rename {internal/command => command}/testdata/show-json/moved/main.tf (100%) rename {internal/command => command}/testdata/show-json/moved/output.json (100%) rename {internal/command => command}/testdata/show-json/moved/terraform.tfstate (100%) rename {internal/command => command}/testdata/show-json/multi-resource-update/main.tf (100%) rename {internal/command => command}/testdata/show-json/multi-resource-update/output.json (100%) rename {internal/command => command}/testdata/show-json/multi-resource-update/terraform.tfstate (100%) rename {internal/command => command}/testdata/show-json/nested-module-error/main.tf (100%) rename {internal/command => command}/testdata/show-json/nested-module-error/modules/main.tf (100%) rename {internal/command => command}/testdata/show-json/nested-module-error/modules/more-modules/main.tf (100%) rename {internal/command => command}/testdata/show-json/nested-modules/main.tf (100%) rename {internal/command => command}/testdata/show-json/nested-modules/modules/main.tf (100%) rename {internal/command => command}/testdata/show-json/nested-modules/modules/more-modules/main.tf (100%) rename {internal/command => command}/testdata/show-json/nested-modules/output.json (100%) rename {internal/command => command}/testdata/show-json/provider-aliasing-conflict/child/main.tf (100%) rename {internal/command => command}/testdata/show-json/provider-aliasing-conflict/main.tf (100%) rename {internal/command => command}/testdata/show-json/provider-aliasing-conflict/output.json (100%) rename {internal/command => command}/testdata/show-json/provider-aliasing-default/child/main.tf (100%) rename {internal/command => command}/testdata/show-json/provider-aliasing-default/child/nested-no-requirements/main.tf (100%) rename {internal/command => command}/testdata/show-json/provider-aliasing-default/child/nested/main.tf (100%) rename {internal/command => command}/testdata/show-json/provider-aliasing-default/main.tf (100%) rename {internal/command => command}/testdata/show-json/provider-aliasing-default/output.json (100%) rename {internal/command => command}/testdata/show-json/provider-aliasing/child/main.tf (100%) rename {internal/command => command}/testdata/show-json/provider-aliasing/child/nested/main.tf (100%) rename {internal/command => command}/testdata/show-json/provider-aliasing/main.tf (100%) rename {internal/command => command}/testdata/show-json/provider-aliasing/output.json (100%) rename {internal/command => command}/testdata/show-json/provider-version-no-config/main.tf (100%) rename {internal/command => command}/testdata/show-json/provider-version-no-config/output.json (100%) rename {internal/command => command}/testdata/show-json/provider-version/main.tf (100%) rename {internal/command => command}/testdata/show-json/provider-version/output.json (100%) rename {internal/command => command}/testdata/show-json/requires-replace/main.tf (100%) rename {internal/command => command}/testdata/show-json/requires-replace/output.json (100%) rename {internal/command => command}/testdata/show-json/requires-replace/terraform.tfstate (100%) rename {internal/command => command}/testdata/show-json/sensitive-values/main.tf (100%) rename {internal/command => command}/testdata/show-json/sensitive-values/output.json (100%) rename {internal/command => command}/testdata/show-json/unknown-output/main.tf (100%) rename {internal/command => command}/testdata/show-json/unknown-output/output.json (100%) rename {internal/command => command}/testdata/show/main.tf (100%) rename {internal/command => command}/testdata/state-list-backend-custom/.terraform/terraform.tfstate (100%) rename {internal/command => command}/testdata/state-list-backend-custom/local-state.tfstate (100%) rename {internal/command => command}/testdata/state-list-backend-custom/main.tf (100%) rename {internal/command => command}/testdata/state-list-backend-default/.terraform/terraform.tfstate (100%) rename {internal/command => command}/testdata/state-list-backend-default/main.tf (100%) rename {internal/command => command}/testdata/state-list-backend-default/terraform.tfstate (100%) rename {internal/command => command}/testdata/state-list-nested-modules/terraform.tfstate (100%) rename {internal/command => command}/testdata/state-pull-backend/.terraform/terraform.tfstate (100%) rename {internal/command => command}/testdata/state-pull-backend/local-state.tfstate (100%) rename {internal/command => command}/testdata/state-pull-backend/main.tf (100%) rename {internal/command => command}/testdata/state-push-bad-lineage/.terraform/terraform.tfstate (100%) rename {internal/command => command}/testdata/state-push-bad-lineage/local-state.tfstate (100%) rename {internal/command => command}/testdata/state-push-bad-lineage/main.tf (100%) rename {internal/command => command}/testdata/state-push-bad-lineage/replace.tfstate (100%) rename {internal/command => command}/testdata/state-push-good/.terraform/terraform.tfstate (100%) rename {internal/command => command}/testdata/state-push-good/main.tf (100%) rename {internal/command => command}/testdata/state-push-good/replace.tfstate (100%) rename {internal/command => command}/testdata/state-push-replace-match/.terraform/terraform.tfstate (100%) rename {internal/command => command}/testdata/state-push-replace-match/local-state.tfstate (100%) rename {internal/command => command}/testdata/state-push-replace-match/main.tf (100%) rename {internal/command => command}/testdata/state-push-replace-match/replace.tfstate (100%) rename {internal/command => command}/testdata/state-push-serial-newer/.terraform/terraform.tfstate (100%) rename {internal/command => command}/testdata/state-push-serial-newer/local-state.tfstate (100%) rename {internal/command => command}/testdata/state-push-serial-newer/main.tf (100%) rename {internal/command => command}/testdata/state-push-serial-newer/replace.tfstate (100%) rename {internal/command => command}/testdata/state-push-serial-older/.terraform/terraform.tfstate (100%) rename {internal/command => command}/testdata/state-push-serial-older/local-state.tfstate (100%) rename {internal/command => command}/testdata/state-push-serial-older/main.tf (100%) rename {internal/command => command}/testdata/state-push-serial-older/replace.tfstate (100%) rename {internal/command => command}/testdata/statelocker.go (89%) rename {internal/command => command}/testdata/test-fails/test-fails.tf (100%) rename {internal/command => command}/testdata/test-fails/tests/hello/hello.tf (100%) rename {internal/command => command}/testdata/test-passes/test-passes.tf (100%) rename {internal/command => command}/testdata/test-passes/tests/hello/hello.tf (100%) rename {internal/command => command}/testdata/validate-invalid/incorrectmodulename/main.tf (100%) rename {internal/command => command}/testdata/validate-invalid/incorrectmodulename/output.json (100%) rename {internal/command => command}/testdata/validate-invalid/interpolation/main.tf (100%) rename {internal/command => command}/testdata/validate-invalid/interpolation/output.json (100%) rename {internal/command => command}/testdata/validate-invalid/main.tf (100%) rename {internal/command => command}/testdata/validate-invalid/missing_defined_var/main.tf (100%) rename {internal/command => command}/testdata/validate-invalid/missing_defined_var/output.json (100%) rename {internal/command => command}/testdata/validate-invalid/missing_quote/main.tf (100%) rename {internal/command => command}/testdata/validate-invalid/missing_quote/output.json (100%) rename {internal/command => command}/testdata/validate-invalid/missing_var/main.tf (100%) rename {internal/command => command}/testdata/validate-invalid/missing_var/output.json (100%) rename {internal/command => command}/testdata/validate-invalid/multiple_modules/main.tf (100%) rename {internal/command => command}/testdata/validate-invalid/multiple_modules/output.json (100%) rename {internal/command => command}/testdata/validate-invalid/multiple_providers/main.tf (100%) rename {internal/command => command}/testdata/validate-invalid/multiple_providers/output.json (100%) rename {internal/command => command}/testdata/validate-invalid/multiple_resources/main.tf (100%) rename {internal/command => command}/testdata/validate-invalid/multiple_resources/output.json (100%) rename {internal/command => command}/testdata/validate-invalid/output.json (100%) rename {internal/command => command}/testdata/validate-invalid/outputs/main.tf (100%) rename {internal/command => command}/testdata/validate-invalid/outputs/output.json (100%) rename {internal/command => command}/testdata/validate-valid/main.tf (100%) rename {internal/command => command}/testdata/validate-valid/output.json (100%) rename {internal/command => command}/testdata/validate-valid/with-tfvars-file/main.tf (100%) rename {internal/command => command}/testdata/validate-valid/with-tfvars-file/terraform.tfvars (100%) rename {internal/command => command}/testdata/variables/main.tf (100%) rename {internal/command => command}/ui_input.go (98%) rename {internal/command => command}/ui_input_test.go (97%) rename {internal/command => command}/unlock.go (95%) rename {internal/command => command}/unlock_test.go (94%) rename {internal/command => command}/untaint.go (94%) rename {internal/command => command}/untaint_test.go (99%) rename {internal/command => command}/validate.go (94%) rename {internal/command => command}/validate_test.go (97%) rename {internal/command => command}/version.go (96%) rename {internal/command => command}/version_test.go (97%) rename {internal/command => command}/views/apply.go (91%) rename {internal/command => command}/views/apply_test.go (96%) rename {internal/command => command}/views/hook_count.go (91%) rename {internal/command => command}/views/hook_count_test.go (96%) rename {internal/command => command}/views/hook_json.go (93%) rename {internal/command => command}/views/hook_json_test.go (97%) rename {internal/command => command}/views/hook_ui.go (96%) rename {internal/command => command}/views/hook_ui_test.go (97%) rename {internal/command => command}/views/json/change.go (98%) rename {internal/command => command}/views/json/change_summary.go (100%) rename {internal/command => command}/views/json/diagnostic.go (99%) rename {internal/command => command}/views/json/diagnostic_test.go (99%) rename {internal/command => command}/views/json/function.go (100%) rename {internal/command => command}/views/json/function_test.go (100%) rename {internal/command => command}/views/json/hook.go (99%) rename {internal/command => command}/views/json/message_types.go (100%) rename {internal/command => command}/views/json/output.go (91%) rename {internal/command => command}/views/json/output_test.go (94%) rename {internal/command => command}/views/json/resource_addr.go (95%) rename {internal/command => command}/views/json/testdata/diagnostic/error-whose-range-starts-at-a-newline.json (100%) rename {internal/command => command}/views/json/testdata/diagnostic/error-with-empty-highlight-range-at-end-of-source-code.json (100%) rename {internal/command => command}/views/json/testdata/diagnostic/error-with-multi-line-snippet.json (100%) rename {internal/command => command}/views/json/testdata/diagnostic/error-with-source-code-subject-and-expression-referring-to-a-collection-containing-a-sensitive-value.json (100%) rename {internal/command => command}/views/json/testdata/diagnostic/error-with-source-code-subject-and-expression-referring-to-sensitive-value-when-not-caused-by-sensitive-values.json (100%) rename {internal/command => command}/views/json/testdata/diagnostic/error-with-source-code-subject-and-expression-referring-to-sensitive-value.json (100%) rename {internal/command => command}/views/json/testdata/diagnostic/error-with-source-code-subject-and-known-expression.json (100%) rename {internal/command => command}/views/json/testdata/diagnostic/error-with-source-code-subject-and-unknown-expression-of-unknown-type-when-not-caused-by-unknown-values.json (100%) rename {internal/command => command}/views/json/testdata/diagnostic/error-with-source-code-subject-and-unknown-expression-of-unknown-type.json (100%) rename {internal/command => command}/views/json/testdata/diagnostic/error-with-source-code-subject-and-unknown-string-expression.json (100%) rename {internal/command => command}/views/json/testdata/diagnostic/error-with-source-code-subject-but-no-context.json (100%) rename {internal/command => command}/views/json/testdata/diagnostic/error-with-source-code-subject-with-multiple-expression-values.json (100%) rename {internal/command => command}/views/json/testdata/diagnostic/error-with-source-code-subject.json (100%) rename {internal/command => command}/views/json/testdata/diagnostic/error-with-source-code-unavailable.json (100%) rename {internal/command => command}/views/json/testdata/diagnostic/error-with-unset-highlight-end-position.json (100%) rename {internal/command => command}/views/json/testdata/diagnostic/sourceless-warning.json (100%) rename {internal/command => command}/views/json_view.go (96%) rename {internal/command => command}/views/json_view_test.go (97%) rename {internal/command => command}/views/operation.go (92%) rename {internal/command => command}/views/operation_test.go (98%) rename {internal/command => command}/views/output.go (97%) rename {internal/command => command}/views/output_test.go (98%) rename {internal/command => command}/views/plan.go (91%) rename {internal/command => command}/views/plan_test.go (92%) rename {internal/command => command}/views/refresh.go (89%) rename {internal/command => command}/views/refresh_test.go (92%) rename {internal/command => command}/views/show.go (86%) rename {internal/command => command}/views/show_test.go (89%) rename {internal/command => command}/views/state_locker.go (97%) rename {internal/command => command}/views/test.go (97%) rename {internal/command => command}/views/test_test.go (81%) rename {internal/command => command}/views/testdata/show/main.tf (100%) rename {internal/command => command}/views/validate.go (94%) rename {internal/command => command}/views/validate_test.go (94%) rename {internal/command => command}/views/view.go (95%) rename {internal/command => command}/webbrowser/mock.go (99%) rename {internal/command => command}/webbrowser/mock_test.go (100%) rename {internal/command => command}/webbrowser/native.go (100%) rename {internal/command => command}/webbrowser/webbrowser.go (100%) rename {internal/command => command}/workdir/dir.go (100%) rename {internal/command => command}/workdir/doc.go (100%) rename {internal/command => command}/workdir/normalize_path.go (100%) rename {internal/command => command}/workdir/plugin_dirs.go (100%) rename {internal/command => command}/workdir/plugin_dirs_test.go (100%) rename {internal/command => command}/workspace_command.go (100%) rename {internal/command => command}/workspace_command_test.go (96%) rename {internal/command => command}/workspace_delete.go (95%) rename {internal/command => command}/workspace_list.go (97%) rename {internal/command => command}/workspace_new.go (94%) rename {internal/command => command}/workspace_select.go (98%) rename {internal/command => command}/workspace_show.go (100%) rename {internal/communicator => communicator}/communicator.go (92%) rename {internal/communicator => communicator}/communicator_mock.go (95%) rename {internal/communicator => communicator}/communicator_test.go (100%) rename {internal/communicator => communicator}/remote/command.go (100%) rename {internal/communicator => communicator}/remote/command_test.go (100%) rename {internal/communicator => communicator}/shared/shared.go (98%) rename {internal/communicator => communicator}/shared/shared_test.go (100%) rename {internal/communicator => communicator}/ssh/communicator.go (99%) rename {internal/communicator => communicator}/ssh/communicator_test.go (99%) rename {internal/communicator => communicator}/ssh/http_proxy.go (100%) rename {internal/communicator => communicator}/ssh/password.go (100%) rename {internal/communicator => communicator}/ssh/password_test.go (100%) rename {internal/communicator => communicator}/ssh/provisioner.go (99%) rename {internal/communicator => communicator}/ssh/provisioner_test.go (100%) rename {internal/communicator => communicator}/ssh/ssh_test.go (100%) rename {internal/communicator => communicator}/winrm/communicator.go (97%) rename {internal/communicator => communicator}/winrm/communicator_test.go (97%) rename {internal/communicator => communicator}/winrm/provisioner.go (98%) rename {internal/communicator => communicator}/winrm/provisioner_test.go (100%) rename {internal/configs => configs}/backend.go (95%) rename {internal/configs => configs}/checks.go (97%) rename {internal/configs => configs}/cloud.go (100%) rename {internal/configs => configs}/compat_shim.go (100%) rename {internal/configs => configs}/config.go (99%) rename {internal/configs => configs}/config_build.go (99%) rename {internal/configs => configs}/config_build_test.go (100%) rename {internal/configs => configs}/config_test.go (99%) rename {internal/configs => configs}/configload/copy_dir.go (100%) rename {internal/configs => configs}/configload/copy_dir_test.go (100%) rename {internal/configs => configs}/configload/doc.go (100%) rename {internal/configs => configs}/configload/inode.go (100%) rename {internal/configs => configs}/configload/inode_freebsd.go (100%) rename {internal/configs => configs}/configload/inode_windows.go (100%) rename {internal/configs => configs}/configload/loader.go (98%) rename {internal/configs => configs}/configload/loader_load.go (98%) rename {internal/configs => configs}/configload/loader_load_test.go (99%) rename {internal/configs => configs}/configload/loader_snapshot.go (99%) rename {internal/configs => configs}/configload/loader_snapshot_test.go (100%) rename {internal/configs => configs}/configload/loader_test.go (100%) rename {internal/configs => configs}/configload/module_mgr.go (94%) rename {internal/configs => configs}/configload/testdata/add-version-constraint/.terraform/modules/child/empty.tf (100%) rename {internal/configs => configs}/configload/testdata/add-version-constraint/.terraform/modules/modules.json (100%) rename {internal/configs => configs}/configload/testdata/add-version-constraint/add-version-constraint.tf (100%) rename {internal/configs => configs}/configload/testdata/already-installed-now-invalid/.terraform/modules/modules.json (100%) rename {internal/configs => configs}/configload/testdata/already-installed-now-invalid/foo/bar/main.tf (100%) rename {internal/configs => configs}/configload/testdata/already-installed-now-invalid/foo/main.tf (100%) rename {internal/configs => configs}/configload/testdata/already-installed-now-invalid/root.tf (100%) rename {internal/configs => configs}/configload/testdata/already-installed/.terraform/modules/child_a/child_a.tf (100%) rename {internal/configs => configs}/configload/testdata/already-installed/.terraform/modules/child_a/child_c/child_c.tf (100%) rename {internal/configs => configs}/configload/testdata/already-installed/.terraform/modules/child_b.child_d/child_d.tf (100%) rename {internal/configs => configs}/configload/testdata/already-installed/.terraform/modules/child_b/child_b.tf (100%) rename {internal/configs => configs}/configload/testdata/already-installed/.terraform/modules/modules.json (100%) rename {internal/configs => configs}/configload/testdata/already-installed/root.tf (100%) rename {internal/configs => configs}/configload/testdata/child-provider-child-count/.terraform/modules/modules.json (100%) rename {internal/configs => configs}/configload/testdata/child-provider-child-count/child-provider-child-count.tf (100%) rename {internal/configs => configs}/configload/testdata/child-provider-child-count/child/child-provider-child-count-child.tf (100%) rename {internal/configs => configs}/configload/testdata/child-provider-child-count/grandchild/child-provider-child-count-grandchild.tf (100%) rename {internal/configs => configs}/configload/testdata/child-provider-grandchild-count/.terraform/modules/modules.json (100%) rename {internal/configs => configs}/configload/testdata/child-provider-grandchild-count/child-provider-grandchild-count.tf (100%) rename {internal/configs => configs}/configload/testdata/child-provider-grandchild-count/child/child-provider-grandchild-count-child.tf (100%) rename {internal/configs => configs}/configload/testdata/child-provider-grandchild-count/grandchild/child-provider-grandchild-count-grandchild.tf (100%) rename {internal/configs => configs}/configload/testdata/empty/.gitignore (100%) rename {internal/configs => configs}/configload/testdata/go-getter-modules/.gitignore (100%) rename {internal/configs => configs}/configload/testdata/go-getter-modules/root.tf (100%) rename {internal/configs => configs}/configload/testdata/invalid-names-in-submodules/.terraform/modules/modules.json (100%) rename {internal/configs => configs}/configload/testdata/invalid-names-in-submodules/main.tf (100%) rename {internal/configs => configs}/configload/testdata/invalid-names-in-submodules/sub/main.tf (100%) rename {internal/configs => configs}/configload/testdata/invalid-names/main.tf (100%) rename {internal/configs => configs}/configload/testdata/local-modules/child_a/child_a.tf (100%) rename {internal/configs => configs}/configload/testdata/local-modules/child_a/child_b/child_b.tf (100%) rename {internal/configs => configs}/configload/testdata/local-modules/root.tf (100%) rename {internal/configs => configs}/configload/testdata/module-depends-on/.terraform/modules/modules.json (100%) rename {internal/configs => configs}/configload/testdata/module-depends-on/child/main.tf (100%) rename {internal/configs => configs}/configload/testdata/module-depends-on/child2/main.tf (100%) rename {internal/configs => configs}/configload/testdata/module-depends-on/root.tf (100%) rename {internal/configs => configs}/configload/testdata/registry-modules/.gitignore (100%) rename {internal/configs => configs}/configload/testdata/registry-modules/root.tf (100%) rename {internal/configs => configs}/configload/testing.go (100%) rename {internal/configs => configs}/configschema/coerce_value.go (100%) rename {internal/configs => configs}/configschema/coerce_value_test.go (99%) rename {internal/configs => configs}/configschema/decoder_spec.go (100%) rename {internal/configs => configs}/configschema/decoder_spec_test.go (100%) rename {internal/configs => configs}/configschema/doc.go (100%) rename {internal/configs => configs}/configschema/empty_value.go (100%) rename {internal/configs => configs}/configschema/empty_value_test.go (100%) rename {internal/configs => configs}/configschema/implied_type.go (100%) rename {internal/configs => configs}/configschema/implied_type_test.go (100%) rename {internal/configs => configs}/configschema/internal_validate.go (100%) rename {internal/configs => configs}/configschema/internal_validate_test.go (100%) rename {internal/configs => configs}/configschema/marks.go (99%) rename {internal/configs => configs}/configschema/marks_test.go (98%) rename {internal/configs => configs}/configschema/nestingmode_string.go (100%) rename {internal/configs => configs}/configschema/none_required.go (100%) rename {internal/configs => configs}/configschema/path.go (100%) rename {internal/configs => configs}/configschema/path_test.go (100%) rename {internal/configs => configs}/configschema/schema.go (100%) rename {internal/configs => configs}/configschema/validate_traversal.go (98%) rename {internal/configs => configs}/configschema/validate_traversal_test.go (100%) rename {internal/configs => configs}/depends_on.go (100%) rename {internal/configs => configs}/doc.go (100%) rename {internal/configs => configs}/escaping_blocks_test.go (100%) rename {internal/configs => configs}/experiments.go (98%) rename {internal/configs => configs}/experiments_test.go (98%) rename {internal/configs => configs}/hcl2shim/flatmap.go (100%) rename {internal/configs => configs}/hcl2shim/flatmap_test.go (100%) rename {internal/configs => configs}/hcl2shim/paths.go (100%) rename {internal/configs => configs}/hcl2shim/paths_test.go (100%) rename {internal/configs => configs}/hcl2shim/single_attr_body.go (100%) rename {internal/configs => configs}/hcl2shim/values.go (99%) rename {internal/configs => configs}/hcl2shim/values_equiv.go (100%) rename {internal/configs => configs}/hcl2shim/values_equiv_test.go (100%) rename {internal/configs => configs}/hcl2shim/values_test.go (99%) rename {internal/configs => configs}/module.go (99%) rename {internal/configs => configs}/module_call.go (98%) rename {internal/configs => configs}/module_call_test.go (99%) rename {internal/configs => configs}/module_merge.go (99%) rename {internal/configs => configs}/module_merge_body.go (100%) rename {internal/configs => configs}/module_merge_test.go (99%) rename {internal/configs => configs}/module_test.go (99%) rename {internal/configs => configs}/moved.go (97%) rename {internal/configs => configs}/moved_test.go (98%) rename {internal/configs => configs}/named_values.go (99%) rename {internal/configs => configs}/parser.go (100%) rename {internal/configs => configs}/parser_config.go (100%) rename {internal/configs => configs}/parser_config_dir.go (100%) rename {internal/configs => configs}/parser_config_dir_test.go (100%) rename {internal/configs => configs}/parser_config_test.go (100%) rename {internal/configs => configs}/parser_test.go (100%) rename {internal/configs => configs}/parser_values.go (100%) rename {internal/configs => configs}/parser_values_test.go (100%) rename {internal/configs => configs}/provider.go (98%) rename {internal/configs => configs}/provider_meta.go (100%) rename {internal/configs => configs}/provider_requirements.go (99%) rename {internal/configs => configs}/provider_requirements_test.go (99%) rename {internal/configs => configs}/provider_test.go (98%) rename {internal/configs => configs}/provider_validation.go (99%) rename {internal/configs => configs}/provisioner.go (100%) rename {internal/configs => configs}/provisioneronfailure_string.go (100%) rename {internal/configs => configs}/provisionerwhen_string.go (100%) rename {internal/configs => configs}/resource.go (99%) rename {internal/configs => configs}/synth_body.go (100%) rename {internal/configs => configs}/synth_body_test.go (100%) rename {internal/configs => configs}/testdata/config-build/child_a/child_a.tf (100%) rename {internal/configs => configs}/testdata/config-build/child_b/child_b.tf (100%) rename {internal/configs => configs}/testdata/config-build/child_c/child_c.tf (100%) rename {internal/configs => configs}/testdata/config-build/root.tf (100%) rename {internal/configs => configs}/testdata/config-diagnostics/empty-configs/main.tf (100%) rename {internal/configs => configs}/testdata/config-diagnostics/empty-configs/mod/main.tf (100%) rename {internal/configs => configs}/testdata/config-diagnostics/empty-configs/warnings (100%) rename {internal/configs => configs}/testdata/config-diagnostics/incorrect-type/errors (100%) rename {internal/configs => configs}/testdata/config-diagnostics/incorrect-type/main.tf (100%) rename {internal/configs => configs}/testdata/config-diagnostics/incorrect-type/mod/main.tf (100%) rename {internal/configs => configs}/testdata/config-diagnostics/incorrect-type/warnings (100%) rename {internal/configs => configs}/testdata/config-diagnostics/invalid-provider/errors (100%) rename {internal/configs => configs}/testdata/config-diagnostics/invalid-provider/main.tf (100%) rename {internal/configs => configs}/testdata/config-diagnostics/invalid-provider/mod/main.tf (100%) rename {internal/configs => configs}/testdata/config-diagnostics/nested-provider/child/child2/main.tf (100%) rename {internal/configs => configs}/testdata/config-diagnostics/nested-provider/child/main.tf (100%) rename {internal/configs => configs}/testdata/config-diagnostics/nested-provider/errors (100%) rename {internal/configs => configs}/testdata/config-diagnostics/nested-provider/root.tf (100%) rename {internal/configs => configs}/testdata/config-diagnostics/override-provider/errors (100%) rename {internal/configs => configs}/testdata/config-diagnostics/override-provider/main.tf (100%) rename {internal/configs => configs}/testdata/config-diagnostics/override-provider/mod/main.tf (100%) rename {internal/configs => configs}/testdata/config-diagnostics/pass-inherited-provider/main.tf (100%) rename {internal/configs => configs}/testdata/config-diagnostics/pass-inherited-provider/mod/main.tf (100%) rename {internal/configs => configs}/testdata/config-diagnostics/pass-inherited-provider/mod2/main.tf (100%) rename {internal/configs => configs}/testdata/config-diagnostics/pass-inherited-provider/warnings (100%) rename {internal/configs => configs}/testdata/config-diagnostics/required-alias/errors (100%) rename {internal/configs => configs}/testdata/config-diagnostics/required-alias/main.tf (100%) rename {internal/configs => configs}/testdata/config-diagnostics/required-alias/mod/main.tf (100%) rename {internal/configs => configs}/testdata/config-diagnostics/unexpected-provider/main.tf (100%) rename {internal/configs => configs}/testdata/config-diagnostics/unexpected-provider/mod/main.tf (100%) rename {internal/configs => configs}/testdata/config-diagnostics/unexpected-provider/warnings (100%) rename {internal/configs => configs}/testdata/config-diagnostics/unknown-root-provider/main.tf (100%) rename {internal/configs => configs}/testdata/config-diagnostics/unknown-root-provider/mod/main.tf (100%) rename {internal/configs => configs}/testdata/config-diagnostics/unknown-root-provider/warnings (100%) rename {internal/configs => configs}/testdata/config-diagnostics/with-depends-on/main.tf (100%) rename {internal/configs => configs}/testdata/config-diagnostics/with-depends-on/mod1/main.tf (100%) rename {internal/configs => configs}/testdata/config-diagnostics/with-depends-on/mod1/mod2/main.tf (100%) rename {internal/configs => configs}/testdata/config-diagnostics/with-depends-on/mod1/mod2/mod3/main.tf (100%) rename {internal/configs => configs}/testdata/dir-empty/.gitkeep (100%) rename {internal/configs => configs}/testdata/duplicate-local-name/main.tf (100%) rename {internal/configs => configs}/testdata/error-files/destroy-provisioners.tf (100%) rename {internal/configs => configs}/testdata/error-files/ignore_changes.tf (100%) rename {internal/configs => configs}/testdata/error-files/invalid_language_edition.tf (100%) rename {internal/configs => configs}/testdata/error-files/module-invalid-registry-source-with-module.tf (100%) rename {internal/configs => configs}/testdata/error-files/module-local-source-with-version.tf (100%) rename {internal/configs => configs}/testdata/error-files/precondition-postcondition-constant.tf (100%) rename {internal/configs => configs}/testdata/error-files/precondition-postcondition-selfref.tf (100%) rename {internal/configs => configs}/testdata/error-files/provider-source-prefix.tf (100%) rename {internal/configs => configs}/testdata/error-files/required-providers-toplevel.tf (100%) rename {internal/configs => configs}/testdata/error-files/unsupported_language_edition.tf (100%) rename {internal/configs => configs}/testdata/error-files/variable_type_quoted.tf (100%) rename {internal/configs => configs}/testdata/error-files/vendor_provisioners.tf (100%) rename {internal/configs => configs}/testdata/escaping-blocks/data/data-escaping-block.tf (100%) rename {internal/configs => configs}/testdata/escaping-blocks/module/child/nothing.tf (100%) rename {internal/configs => configs}/testdata/escaping-blocks/module/module-escaping-block.tf (100%) rename {internal/configs => configs}/testdata/escaping-blocks/provider/provider-escaping-block.tf (100%) rename {internal/configs => configs}/testdata/escaping-blocks/resource/resource-escaping-block.tf (100%) rename {internal/configs => configs}/testdata/experiments/concluded/concluded_experiment.tf (100%) rename {internal/configs => configs}/testdata/experiments/current/current_experiment.tf (100%) rename {internal/configs => configs}/testdata/experiments/invalid/invalid_experiments.tf (100%) rename {internal/configs => configs}/testdata/experiments/unknown/unknown_experiment.tf (100%) rename {internal/configs => configs}/testdata/invalid-files/data-count-and-for_each.tf (100%) rename {internal/configs => configs}/testdata/invalid-files/data-invalid-provider-reference.tf (100%) rename {internal/configs => configs}/testdata/invalid-files/data-reserved-locals.tf (100%) rename {internal/configs => configs}/testdata/invalid-files/data-resource-lifecycle.tf (100%) rename {internal/configs => configs}/testdata/invalid-files/everything-is-a-plan.tf (100%) rename {internal/configs => configs}/testdata/invalid-files/interp-in-data-label.tf (100%) rename {internal/configs => configs}/testdata/invalid-files/interp-in-rsrc-label.tf (100%) rename {internal/configs => configs}/testdata/invalid-files/json-as-native-syntax.tf (100%) rename {internal/configs => configs}/testdata/invalid-files/module-calls.tf (100%) rename {internal/configs => configs}/testdata/invalid-files/native-syntax-as-json.tf.json (100%) rename {internal/configs => configs}/testdata/invalid-files/precondition-postcondition-badref.tf (100%) rename {internal/configs => configs}/testdata/invalid-files/precondition-postcondition-missing-condition.tf (100%) rename {internal/configs => configs}/testdata/invalid-files/provider-localname-normalization.tf (100%) rename {internal/configs => configs}/testdata/invalid-files/provider-reserved.tf (100%) rename {internal/configs => configs}/testdata/invalid-files/provider-syntax.tf (100%) rename {internal/configs => configs}/testdata/invalid-files/resource-count-and-for_each.tf (100%) rename {internal/configs => configs}/testdata/invalid-files/resource-invalid-provider-reference.tf (100%) rename {internal/configs => configs}/testdata/invalid-files/resource-lifecycle-badbool.tf (100%) rename {internal/configs => configs}/testdata/invalid-files/resource-name-invalid.tf (100%) rename {internal/configs => configs}/testdata/invalid-files/resource-reserved-locals.tf (100%) rename {internal/configs => configs}/testdata/invalid-files/resources-ignorechanges-all-legacymix.tf (100%) rename {internal/configs => configs}/testdata/invalid-files/triggered-invalid-each.tf (100%) rename {internal/configs => configs}/testdata/invalid-files/triggered-invalid-expression.tf (100%) rename {internal/configs => configs}/testdata/invalid-files/unexpected-attr.tf (100%) rename {internal/configs => configs}/testdata/invalid-files/unexpected-block.tf (100%) rename {internal/configs => configs}/testdata/invalid-files/variable-bad-default.tf (100%) rename {internal/configs => configs}/testdata/invalid-files/variable-bad-sensitive.tf (100%) rename {internal/configs => configs}/testdata/invalid-files/variable-type-unknown.tf (100%) rename {internal/configs => configs}/testdata/invalid-files/variable-validation-condition-badref.tf (100%) rename {internal/configs => configs}/testdata/invalid-files/variable-validation-condition-noref.tf (100%) rename {internal/configs => configs}/testdata/invalid-files/version-variable.tf (100%) rename {internal/configs => configs}/testdata/invalid-files/zerolen.tf.json (100%) rename {internal/configs => configs}/testdata/invalid-modules/multiple-required-providers/a.tf (100%) rename {internal/configs => configs}/testdata/invalid-modules/multiple-required-providers/b.tf (100%) rename {internal/configs => configs}/testdata/invalid-modules/nullable-with-default-null/main.tf (100%) rename {internal/configs => configs}/testdata/invalid-modules/override-cloud-duplicates/main.tf (100%) rename {internal/configs => configs}/testdata/invalid-modules/override-cloud-duplicates/override.tf (100%) rename {internal/configs => configs}/testdata/invalid-modules/override-nonexist-variable/override.tf (100%) rename {internal/configs => configs}/testdata/invalid-modules/override-variable-causes-bad-default/base.tf (100%) rename {internal/configs => configs}/testdata/invalid-modules/override-variable-causes-bad-default/override.tf (100%) rename {internal/configs => configs}/testdata/invalid-modules/provider-meta/invalid-interpolation.tf (100%) rename {internal/configs => configs}/testdata/nested-backend-warning/child/child.tf (100%) rename {internal/configs => configs}/testdata/nested-backend-warning/root.tf (100%) rename {internal/configs => configs}/testdata/nested-cloud-warning/child/child.tf (100%) rename {internal/configs => configs}/testdata/nested-cloud-warning/root.tf (100%) rename {internal/configs => configs}/testdata/nested-errors/child_a/child_a.tf (100%) rename {internal/configs => configs}/testdata/nested-errors/child_c/child_c.tf (100%) rename {internal/configs => configs}/testdata/nested-errors/root.tf (100%) rename {internal/configs => configs}/testdata/provider-reqs/child/grandchild/provider-reqs-grandchild.tf (100%) rename {internal/configs => configs}/testdata/provider-reqs/child/provider-reqs-child.tf (100%) rename {internal/configs => configs}/testdata/provider-reqs/provider-reqs-root.tf (100%) rename {internal/configs => configs}/testdata/providers-explicit-fqn/root.tf (100%) rename {internal/configs => configs}/testdata/valid-files/backend.tf (100%) rename {internal/configs => configs}/testdata/valid-files/cloud.tf (100%) rename {internal/configs => configs}/testdata/valid-files/data-sources.tf (100%) rename {internal/configs => configs}/testdata/valid-files/empty.tf (100%) rename {internal/configs => configs}/testdata/valid-files/empty.tf.json (100%) rename {internal/configs => configs}/testdata/valid-files/locals.tf (100%) rename {internal/configs => configs}/testdata/valid-files/locals.tf.json (100%) rename {internal/configs => configs}/testdata/valid-files/object-optional-attrs.tf (100%) rename {internal/configs => configs}/testdata/valid-files/outputs.tf (100%) rename {internal/configs => configs}/testdata/valid-files/preconditions-postconditions.tf (100%) rename {internal/configs => configs}/testdata/valid-files/provider-configs.tf (100%) rename {internal/configs => configs}/testdata/valid-files/providers-explicit-implied.tf (100%) rename {internal/configs => configs}/testdata/valid-files/references.tf.json (100%) rename {internal/configs => configs}/testdata/valid-files/required-providers.tf (100%) rename {internal/configs => configs}/testdata/valid-files/required-version.tf (100%) rename {internal/configs => configs}/testdata/valid-files/resources-ignorechanges-all.tf (100%) rename {internal/configs => configs}/testdata/valid-files/resources-ignorechanges-all.tf.json (100%) rename {internal/configs => configs}/testdata/valid-files/resources.tf (100%) rename {internal/configs => configs}/testdata/valid-files/resources.tf.json (100%) rename {internal/configs => configs}/testdata/valid-files/valid-language-edition.tf (100%) rename {internal/configs => configs}/testdata/valid-files/variable_validation.tf (100%) rename {internal/configs => configs}/testdata/valid-files/variables.tf (100%) rename {internal/configs => configs}/testdata/valid-files/variables.tf.json (100%) rename {internal/configs => configs}/testdata/valid-modules/empty/README (100%) rename {internal/configs => configs}/testdata/valid-modules/implied-providers/providers.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/implied-providers/resources.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/moved-blocks/moved-blocks-1.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/moved-blocks/moved-blocks-2.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/nested-providers-fqns/child/main.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/nested-providers-fqns/main.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/override-backend-no-base/main.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/override-backend-no-base/override.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/override-backend-with-cloud/main.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/override-backend-with-cloud/override.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/override-backend/main.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/override-backend/override.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/override-cloud-no-base/main.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/override-cloud-no-base/override.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/override-cloud/main.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/override-cloud/override.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/override-dynamic-block-base/a_override.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/override-dynamic-block-base/base.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/override-dynamic-block-override/a_override.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/override-dynamic-block-override/base.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/override-ignore-changes/main.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/override-ignore-changes/main_override.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/override-module/a_override.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/override-module/b_override.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/override-module/primary.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/override-output-sensitive/override.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/override-output-sensitive/primary.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/override-resource-provider/a_override.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/override-resource-provider/base.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/override-variable-sensitive/a_override.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/override-variable-sensitive/b_override.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/override-variable-sensitive/primary.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/override-variable/a_override.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/override-variable/b_override.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/override-variable/primary.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/provider-aliases/main.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/provider-meta/main.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/providers-fqns/main.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/required-providers-after-resource/main.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/required-providers-after-resource/providers.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/required-providers-overrides/bar_provider_override.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/required-providers-overrides/main.tf (100%) rename {internal/configs => configs}/testdata/valid-modules/required-providers-overrides/providers.tf (100%) rename {internal/configs => configs}/testdata/warning-files/depends_on.tf (100%) rename {internal/configs => configs}/testdata/warning-files/provider_ref.tf (100%) rename {internal/configs => configs}/testdata/warning-files/provisioner_keyword.tf (100%) rename {internal/configs => configs}/util.go (100%) rename {internal/configs => configs}/variable_type_hint.go (100%) rename {internal/configs => configs}/variabletypehint_string.go (100%) rename {internal/configs => configs}/version_constraint.go (100%) rename {internal/copy => copy}/copy_dir.go (100%) rename {internal/copy => copy}/copy_dir_test.go (100%) rename {internal/copy => copy}/copy_file.go (100%) rename {internal/dag => dag}/dag.go (99%) rename {internal/dag => dag}/dag_test.go (99%) rename {internal/dag => dag}/dot.go (100%) rename {internal/dag => dag}/dot_test.go (100%) rename {internal/dag => dag}/edge.go (100%) rename {internal/dag => dag}/edge_test.go (100%) rename {internal/dag => dag}/graph.go (100%) rename {internal/dag => dag}/graph_test.go (100%) rename {internal/dag => dag}/marshal.go (100%) rename {internal/dag => dag}/marshal_test.go (100%) rename {internal/dag => dag}/set.go (100%) rename {internal/dag => dag}/set_test.go (100%) rename {internal/dag => dag}/tarjan.go (100%) rename {internal/dag => dag}/tarjan_test.go (100%) rename {internal/dag => dag}/walk.go (99%) rename {internal/dag => dag}/walk_test.go (99%) rename {internal/depsfile => depsfile}/doc.go (100%) rename {internal/depsfile => depsfile}/locks.go (99%) rename {internal/depsfile => depsfile}/locks_file.go (98%) rename {internal/depsfile => depsfile}/locks_file_test.go (98%) rename {internal/depsfile => depsfile}/locks_test.go (98%) rename {internal/depsfile => depsfile}/paths.go (100%) rename {internal/depsfile => depsfile}/testdata/locks-files/empty.hcl (100%) rename {internal/depsfile => depsfile}/testdata/locks-files/invalid-provider-addrs.hcl (100%) rename {internal/depsfile => depsfile}/testdata/locks-files/invalid-versions.hcl (100%) rename {internal/depsfile => depsfile}/testdata/locks-files/unsupported-block.hcl (100%) rename {internal/depsfile => depsfile}/testdata/locks-files/valid-provider-locks.hcl (100%) rename {internal/depsfile => depsfile}/testing.go (100%) rename {internal/didyoumean => didyoumean}/name_suggestion.go (100%) rename {internal/didyoumean => didyoumean}/name_suggestion_test.go (100%) rename {internal/e2e => e2e}/e2e.go (97%) rename {internal/earlyconfig => earlyconfig}/config.go (96%) rename {internal/earlyconfig => earlyconfig}/config_build.go (98%) rename {internal/earlyconfig => earlyconfig}/config_test.go (94%) rename {internal/earlyconfig => earlyconfig}/diagnostics.go (97%) rename {internal/earlyconfig => earlyconfig}/doc.go (100%) rename {internal/earlyconfig => earlyconfig}/module.go (86%) rename {internal/earlyconfig => earlyconfig}/testdata/provider-reqs/child/provider-reqs-child.tf (100%) rename {internal/earlyconfig => earlyconfig}/testdata/provider-reqs/provider-reqs-root.tf (100%) rename {internal/experiments => experiments}/doc.go (100%) rename {internal/experiments => experiments}/errors.go (100%) rename {internal/experiments => experiments}/experiment.go (100%) rename {internal/experiments => experiments}/set.go (100%) rename {internal/experiments => experiments}/testing.go (100%) rename {internal/getmodules => getmodules}/doc.go (100%) rename {internal/getmodules => getmodules}/file_detector.go (100%) rename {internal/getmodules => getmodules}/getter.go (99%) rename {internal/getmodules => getmodules}/installer.go (100%) rename {internal/getmodules => getmodules}/package.go (100%) rename {internal/getmodules => getmodules}/subdir.go (100%) rename {internal/getproviders => getproviders}/didyoumean.go (99%) rename {internal/getproviders => getproviders}/didyoumean_test.go (99%) rename {internal/getproviders => getproviders}/doc.go (100%) rename {internal/getproviders => getproviders}/errors.go (99%) rename {internal/getproviders => getproviders}/filesystem_mirror_source.go (98%) rename {internal/getproviders => getproviders}/filesystem_mirror_source_test.go (99%) rename {internal/getproviders => getproviders}/filesystem_search.go (99%) rename {internal/getproviders => getproviders}/filesystem_search_test.go (96%) rename {internal/getproviders => getproviders}/hanging_source.go (93%) rename {internal/getproviders => getproviders}/hash.go (100%) rename {internal/getproviders => getproviders}/hash_test.go (100%) rename {internal/getproviders => getproviders}/http_mirror_source.go (98%) rename {internal/getproviders => getproviders}/http_mirror_source_test.go (99%) rename {internal/getproviders => getproviders}/memoize_source.go (98%) rename {internal/getproviders => getproviders}/memoize_source_test.go (99%) rename {internal/getproviders => getproviders}/mock_source.go (99%) rename {internal/getproviders => getproviders}/multi_source.go (99%) rename {internal/getproviders => getproviders}/multi_source_test.go (99%) rename {internal/getproviders => getproviders}/package_authentication.go (100%) rename {internal/getproviders => getproviders}/package_authentication_test.go (100%) rename {internal/getproviders => getproviders}/public_keys.go (100%) rename {internal/getproviders => getproviders}/registry_client.go (99%) rename {internal/getproviders => getproviders}/registry_client_test.go (99%) rename {internal/getproviders => getproviders}/registry_source.go (99%) rename {internal/getproviders => getproviders}/registry_source_test.go (99%) rename {internal/getproviders => getproviders}/source.go (89%) rename {internal/getproviders => getproviders}/testdata/filesystem-mirror-invalid/hashicorp/null/2.0.0/darwin_amd64/terraform-provider-null (100%) rename {internal/getproviders => getproviders}/testdata/filesystem-mirror-invalid/hashicorp/null/2.0.0/linux_amd64/terraform-provider-null (100%) rename {internal/getproviders => getproviders}/testdata/filesystem-mirror-invalid/hashicorp/null/invalid (100%) rename {internal/getproviders => getproviders}/testdata/filesystem-mirror-invalid/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip (100%) rename {internal/getproviders => getproviders}/testdata/filesystem-mirror-invalid/hashicorp/null/terraform-provider-null_invalid.zip (100%) rename {internal/getproviders => getproviders}/testdata/filesystem-mirror-invalid/hashicorp/null/terraform-provider-null_invalid_invalid_invalid.zip (100%) rename {internal/getproviders => getproviders}/testdata/filesystem-mirror-invalid/hashicorp/random-beta/1.2.0/linux_amd64/terraform-provider-random-beta (100%) rename {internal/getproviders => getproviders}/testdata/filesystem-mirror-invalid/hashicorp/random/1.2.0/linux_amd64/terraform-provider-random (100%) rename {internal/getproviders => getproviders}/testdata/filesystem-mirror/registry.terraform.io/-/legacy/1.0.0/linux_amd64/terraform-provider-legacy (100%) rename {internal/getproviders => getproviders}/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/2.0.0/darwin_amd64/terraform-provider-null (100%) rename {internal/getproviders => getproviders}/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/2.0.0/linux_amd64/terraform-provider-null (100%) rename {internal/getproviders => getproviders}/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/invalid (100%) rename {internal/getproviders => getproviders}/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip (100%) rename {internal/getproviders => getproviders}/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/terraform-provider-null_invalid.zip (100%) rename {internal/getproviders => getproviders}/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/terraform-provider-null_invalid_invalid_invalid.zip (100%) rename {internal/getproviders => getproviders}/testdata/filesystem-mirror/registry.terraform.io/hashicorp/random-beta/1.2.0/linux_amd64/terraform-provider-random-beta (100%) rename {internal/getproviders => getproviders}/testdata/filesystem-mirror/registry.terraform.io/hashicorp/random/1.2.0/linux_amd64/terraform-provider-random (100%) rename {internal/getproviders => getproviders}/testdata/filesystem-mirror/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64/extra-data.txt (100%) rename {internal/getproviders => getproviders}/testdata/filesystem-mirror/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64/terraform-provider-happycloud (100%) rename {internal/getproviders => getproviders}/testdata/search-local-directory/symlinks/real/example.com/foo/bar/1.0.0/linux_amd64/terraform-provider-bar (100%) rename {internal/getproviders => getproviders}/testdata/search-local-directory/symlinks/real/example.net (100%) rename {internal/getproviders => getproviders}/testdata/search-local-directory/symlinks/symlink (100%) rename {internal/getproviders => getproviders}/types.go (99%) rename {internal/getproviders => getproviders}/types_test.go (100%) rename {internal/grpcwrap => grpcwrap}/provider.go (98%) rename {internal/grpcwrap => grpcwrap}/provider6.go (98%) rename {internal/grpcwrap => grpcwrap}/provisioner.go (91%) rename {internal/helper => helper}/slowmessage/slowmessage.go (100%) rename {internal/helper => helper}/slowmessage/slowmessage_test.go (100%) rename {internal/httpclient => httpclient}/client.go (100%) rename {internal/httpclient => httpclient}/client_test.go (100%) rename {internal/httpclient => httpclient}/useragent.go (100%) rename {internal/httpclient => httpclient}/useragent_test.go (100%) rename {internal/initwd => initwd}/doc.go (100%) rename {internal/initwd => initwd}/from_module.go (97%) rename {internal/initwd => initwd}/from_module_test.go (97%) rename {internal/initwd => initwd}/load_config.go (91%) rename {internal/initwd => initwd}/module_install.go (98%) rename {internal/initwd => initwd}/module_install_hooks.go (100%) rename {internal/initwd => initwd}/module_install_test.go (98%) rename {internal/initwd => initwd}/testdata/already-installed/root.tf (100%) rename {internal/initwd => initwd}/testdata/empty/.gitignore (100%) rename {internal/initwd => initwd}/testdata/go-getter-modules/.gitignore (100%) rename {internal/initwd => initwd}/testdata/go-getter-modules/root.tf (100%) rename {internal/initwd => initwd}/testdata/invalid-version-constraint-local/.gitignore (100%) rename {internal/initwd => initwd}/testdata/invalid-version-constraint-local/root.tf (100%) rename {internal/initwd => initwd}/testdata/invalid-version-constraint/.gitignore (100%) rename {internal/initwd => initwd}/testdata/invalid-version-constraint/root.tf (100%) rename {internal/initwd => initwd}/testdata/load-module-package-escape/child/package-escape-child.tf (100%) rename {internal/initwd => initwd}/testdata/load-module-package-escape/grandchild/package-escape-grandchild.tf (100%) rename {internal/initwd => initwd}/testdata/load-module-package-escape/package-escape.tf (100%) rename {internal/initwd => initwd}/testdata/load-module-package-prefix/package-prefix.tf (100%) rename {internal/initwd => initwd}/testdata/load-module-package-prefix/package/child/package-prefix-child.tf (100%) rename {internal/initwd => initwd}/testdata/load-module-package-prefix/package/grandchild/package-prefix-grandchild.tf (100%) rename {internal/initwd => initwd}/testdata/local-module-error/child_a/main.tf (100%) rename {internal/initwd => initwd}/testdata/local-module-error/main.tf (100%) rename {internal/initwd => initwd}/testdata/local-module-symlink/child_a/child_a.tf (100%) rename {internal/initwd => initwd}/testdata/local-module-symlink/child_a/child_b/child_b.tf (100%) rename {internal/initwd => initwd}/testdata/local-module-symlink/modules/child_a (100%) rename {internal/initwd => initwd}/testdata/local-module-symlink/root.tf (100%) rename {internal/initwd => initwd}/testdata/local-modules/child_a/child_a.tf (100%) rename {internal/initwd => initwd}/testdata/local-modules/child_a/child_b/child_b.tf (100%) rename {internal/initwd => initwd}/testdata/local-modules/root.tf (100%) rename {internal/initwd => initwd}/testdata/prerelease-version-constraint-match/root.tf (100%) rename {internal/initwd => initwd}/testdata/prerelease-version-constraint/root.tf (100%) rename {internal/initwd => initwd}/testdata/registry-modules/.gitignore (100%) rename {internal/initwd => initwd}/testdata/registry-modules/root.tf (100%) rename {internal/initwd => initwd}/testing.go (92%) rename {internal/instances => instances}/expander.go (99%) rename {internal/instances => instances}/expander_test.go (99%) rename {internal/instances => instances}/expansion_mode.go (97%) rename {internal/instances => instances}/instance_key_data.go (100%) rename {internal/instances => instances}/set.go (97%) rename {internal/instances => instances}/set_test.go (99%) delete mode 100644 internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64/terraform-provider-null.exe delete mode 100644 internal/plugin/discovery/testdata/current-style-plugins/mockos_mockarch/terraform-foo-bar_v1.0.0.exe delete mode 100644 internal/plugin/mock_proto/generate.go delete mode 100644 internal/provider-simple-v6/main/main.go delete mode 100644 internal/provider-simple/main/main.go delete mode 100644 internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64/terraform-provider-null.exe delete mode 100644 internal/terraform/context.go delete mode 100644 internal/terraform/context_apply.go delete mode 100644 internal/terraform/context_apply2_test.go delete mode 100644 internal/terraform/context_apply_test.go delete mode 100644 internal/terraform/context_eval.go delete mode 100644 internal/terraform/context_eval_test.go delete mode 100644 internal/terraform/context_fixtures_test.go delete mode 100644 internal/terraform/context_import.go delete mode 100644 internal/terraform/context_import_test.go delete mode 100644 internal/terraform/context_input.go delete mode 100644 internal/terraform/context_input_test.go delete mode 100644 internal/terraform/context_plan.go delete mode 100644 internal/terraform/context_plan2_test.go delete mode 100644 internal/terraform/context_plan_test.go delete mode 100644 internal/terraform/context_plugins.go delete mode 100644 internal/terraform/context_plugins_test.go delete mode 100644 internal/terraform/context_refresh.go delete mode 100644 internal/terraform/context_refresh_test.go delete mode 100644 internal/terraform/context_test.go delete mode 100644 internal/terraform/context_validate.go delete mode 100644 internal/terraform/context_validate_test.go delete mode 100644 internal/terraform/context_walk.go delete mode 100644 internal/terraform/diagnostics.go delete mode 100644 internal/terraform/eval_conditions.go delete mode 100644 internal/terraform/eval_context.go delete mode 100644 internal/terraform/eval_context_builtin.go delete mode 100644 internal/terraform/eval_context_builtin_test.go delete mode 100644 internal/terraform/eval_context_mock.go delete mode 100644 internal/terraform/eval_count.go delete mode 100644 internal/terraform/eval_count_test.go delete mode 100644 internal/terraform/eval_for_each.go delete mode 100644 internal/terraform/eval_for_each_test.go delete mode 100644 internal/terraform/eval_provider.go delete mode 100644 internal/terraform/eval_provider_test.go delete mode 100644 internal/terraform/eval_variable.go delete mode 100644 internal/terraform/eval_variable_test.go delete mode 100644 internal/terraform/evaluate.go delete mode 100644 internal/terraform/evaluate_test.go delete mode 100644 internal/terraform/evaluate_triggers.go delete mode 100644 internal/terraform/evaluate_triggers_test.go delete mode 100644 internal/terraform/evaluate_valid.go delete mode 100644 internal/terraform/evaluate_valid_test.go delete mode 100644 internal/terraform/execute.go delete mode 100644 internal/terraform/features.go delete mode 100644 internal/terraform/graph.go delete mode 100644 internal/terraform/graph_builder.go delete mode 100644 internal/terraform/graph_builder_apply.go delete mode 100644 internal/terraform/graph_builder_apply_test.go delete mode 100644 internal/terraform/graph_builder_eval.go delete mode 100644 internal/terraform/graph_builder_plan.go delete mode 100644 internal/terraform/graph_builder_plan_test.go delete mode 100644 internal/terraform/graph_builder_test.go delete mode 100644 internal/terraform/graph_dot.go delete mode 100644 internal/terraform/graph_dot_test.go delete mode 100644 internal/terraform/graph_interface_subgraph.go delete mode 100644 internal/terraform/graph_test.go delete mode 100644 internal/terraform/graph_walk.go delete mode 100644 internal/terraform/graph_walk_context.go delete mode 100644 internal/terraform/graph_walk_operation.go delete mode 100644 internal/terraform/graph_walk_test.go delete mode 100644 internal/terraform/hook.go delete mode 100644 internal/terraform/hook_mock.go delete mode 100644 internal/terraform/hook_stop.go delete mode 100644 internal/terraform/hook_stop_test.go delete mode 100644 internal/terraform/hook_test.go delete mode 100644 internal/terraform/instance_expanders.go delete mode 100644 internal/terraform/marks.go delete mode 100644 internal/terraform/marks_test.go delete mode 100644 internal/terraform/node_data_destroy.go delete mode 100644 internal/terraform/node_data_destroy_test.go delete mode 100644 internal/terraform/node_local.go delete mode 100644 internal/terraform/node_local_test.go delete mode 100644 internal/terraform/node_module_expand.go delete mode 100644 internal/terraform/node_module_expand_test.go delete mode 100644 internal/terraform/node_module_variable.go delete mode 100644 internal/terraform/node_module_variable_test.go delete mode 100644 internal/terraform/node_output.go delete mode 100644 internal/terraform/node_output_test.go delete mode 100644 internal/terraform/node_provider.go delete mode 100644 internal/terraform/node_provider_abstract.go delete mode 100644 internal/terraform/node_provider_eval.go delete mode 100644 internal/terraform/node_provider_test.go delete mode 100644 internal/terraform/node_resource_abstract.go delete mode 100644 internal/terraform/node_resource_abstract_instance.go delete mode 100644 internal/terraform/node_resource_abstract_instance_test.go delete mode 100644 internal/terraform/node_resource_abstract_test.go delete mode 100644 internal/terraform/node_resource_apply.go delete mode 100644 internal/terraform/node_resource_apply_instance.go delete mode 100644 internal/terraform/node_resource_apply_test.go delete mode 100644 internal/terraform/node_resource_destroy.go delete mode 100644 internal/terraform/node_resource_destroy_deposed.go delete mode 100644 internal/terraform/node_resource_destroy_deposed_test.go delete mode 100644 internal/terraform/node_resource_import.go delete mode 100644 internal/terraform/node_resource_plan.go delete mode 100644 internal/terraform/node_resource_plan_destroy.go delete mode 100644 internal/terraform/node_resource_plan_instance.go delete mode 100644 internal/terraform/node_resource_plan_orphan.go delete mode 100644 internal/terraform/node_resource_plan_orphan_test.go delete mode 100644 internal/terraform/node_resource_validate.go delete mode 100644 internal/terraform/node_resource_validate_test.go delete mode 100644 internal/terraform/node_root_variable.go delete mode 100644 internal/terraform/node_root_variable_test.go delete mode 100644 internal/terraform/node_value.go delete mode 100644 internal/terraform/phasestate_string.go delete mode 100644 internal/terraform/provider_mock.go delete mode 100644 internal/terraform/provisioner_mock.go delete mode 100644 internal/terraform/provisioner_mock_test.go delete mode 100644 internal/terraform/reduce_plan.go delete mode 100644 internal/terraform/reduce_plan_test.go delete mode 100644 internal/terraform/resource_provider_mock_test.go delete mode 100644 internal/terraform/schemas.go delete mode 100644 internal/terraform/schemas_test.go delete mode 100644 internal/terraform/terraform_test.go delete mode 100644 internal/terraform/testdata/apply-blank/main.tf delete mode 100644 internal/terraform/testdata/apply-cancel-block/main.tf delete mode 100644 internal/terraform/testdata/apply-cancel-provisioner/main.tf delete mode 100644 internal/terraform/testdata/apply-cancel/main.tf delete mode 100644 internal/terraform/testdata/apply-cbd-count/main.tf delete mode 100644 internal/terraform/testdata/apply-cbd-cycle/main.tf delete mode 100644 internal/terraform/testdata/apply-cbd-depends-non-cbd/main.tf delete mode 100644 internal/terraform/testdata/apply-cbd-deposed-only/main.tf delete mode 100644 internal/terraform/testdata/apply-compute/main.tf delete mode 100644 internal/terraform/testdata/apply-count-dec-one/main.tf delete mode 100644 internal/terraform/testdata/apply-count-dec/main.tf delete mode 100644 internal/terraform/testdata/apply-count-tainted/main.tf delete mode 100644 internal/terraform/testdata/apply-count-variable-ref/main.tf delete mode 100644 internal/terraform/testdata/apply-count-variable/main.tf delete mode 100644 internal/terraform/testdata/apply-data-basic/main.tf delete mode 100644 internal/terraform/testdata/apply-data-sensitive/main.tf delete mode 100644 internal/terraform/testdata/apply-depends-create-before/main.tf delete mode 100644 internal/terraform/testdata/apply-destroy-cbd/main.tf delete mode 100644 internal/terraform/testdata/apply-destroy-computed/child/main.tf delete mode 100644 internal/terraform/testdata/apply-destroy-computed/main.tf delete mode 100644 internal/terraform/testdata/apply-destroy-cross-providers/child/main.tf delete mode 100644 internal/terraform/testdata/apply-destroy-cross-providers/main.tf delete mode 100644 internal/terraform/testdata/apply-destroy-data-cycle/main.tf delete mode 100644 internal/terraform/testdata/apply-destroy-data-resource/main.tf delete mode 100644 internal/terraform/testdata/apply-destroy-deeply-nested-module/child/main.tf delete mode 100644 internal/terraform/testdata/apply-destroy-deeply-nested-module/child/subchild/main.tf delete mode 100644 internal/terraform/testdata/apply-destroy-deeply-nested-module/child/subchild/subsubchild/main.tf delete mode 100644 internal/terraform/testdata/apply-destroy-deeply-nested-module/main.tf delete mode 100644 internal/terraform/testdata/apply-destroy-depends-on/main.tf delete mode 100644 internal/terraform/testdata/apply-destroy-mod-var-and-count-nested/child/child2/main.tf delete mode 100644 internal/terraform/testdata/apply-destroy-mod-var-and-count-nested/child/main.tf delete mode 100644 internal/terraform/testdata/apply-destroy-mod-var-and-count-nested/main.tf delete mode 100644 internal/terraform/testdata/apply-destroy-mod-var-and-count/child/main.tf delete mode 100644 internal/terraform/testdata/apply-destroy-mod-var-and-count/main.tf delete mode 100644 internal/terraform/testdata/apply-destroy-mod-var-provider-config/child/child.tf delete mode 100644 internal/terraform/testdata/apply-destroy-mod-var-provider-config/main.tf delete mode 100644 internal/terraform/testdata/apply-destroy-module-resource-prefix/child/main.tf delete mode 100644 internal/terraform/testdata/apply-destroy-module-resource-prefix/main.tf delete mode 100644 internal/terraform/testdata/apply-destroy-module-with-attrs/child/main.tf delete mode 100644 internal/terraform/testdata/apply-destroy-module-with-attrs/main.tf delete mode 100644 internal/terraform/testdata/apply-destroy-nested-module-with-attrs/middle/bottom/bottom.tf delete mode 100644 internal/terraform/testdata/apply-destroy-nested-module-with-attrs/middle/middle.tf delete mode 100644 internal/terraform/testdata/apply-destroy-nested-module-with-attrs/top.tf delete mode 100644 internal/terraform/testdata/apply-destroy-nested-module/child/main.tf delete mode 100644 internal/terraform/testdata/apply-destroy-nested-module/child/subchild/main.tf delete mode 100644 internal/terraform/testdata/apply-destroy-nested-module/main.tf delete mode 100644 internal/terraform/testdata/apply-destroy-outputs/main.tf delete mode 100644 internal/terraform/testdata/apply-destroy-provisioner/main.tf delete mode 100644 internal/terraform/testdata/apply-destroy-tainted/main.tf delete mode 100644 internal/terraform/testdata/apply-destroy-targeted-count/main.tf delete mode 100644 internal/terraform/testdata/apply-destroy-with-locals/main.tf delete mode 100644 internal/terraform/testdata/apply-destroy/main.tf delete mode 100644 internal/terraform/testdata/apply-empty-module/child/main.tf delete mode 100644 internal/terraform/testdata/apply-empty-module/main.tf delete mode 100644 internal/terraform/testdata/apply-error-create-before/main.tf delete mode 100644 internal/terraform/testdata/apply-error/main.tf delete mode 100644 internal/terraform/testdata/apply-escape/main.tf delete mode 100644 internal/terraform/testdata/apply-good-create-before-update/main.tf delete mode 100644 internal/terraform/testdata/apply-good-create-before/main.tf delete mode 100644 internal/terraform/testdata/apply-good/main.tf delete mode 100644 internal/terraform/testdata/apply-idattr/main.tf delete mode 100644 internal/terraform/testdata/apply-ignore-changes-all/main.tf delete mode 100644 internal/terraform/testdata/apply-ignore-changes-create/main.tf delete mode 100644 internal/terraform/testdata/apply-ignore-changes-dep/main.tf delete mode 100644 internal/terraform/testdata/apply-inconsistent-with-plan/main.tf delete mode 100644 internal/terraform/testdata/apply-interpolated-count/main.tf delete mode 100644 internal/terraform/testdata/apply-invalid-index/main.tf delete mode 100644 internal/terraform/testdata/apply-issue19908/issue19908.tf delete mode 100644 internal/terraform/testdata/apply-local-val/child/child.tf delete mode 100644 internal/terraform/testdata/apply-local-val/main.tf delete mode 100644 internal/terraform/testdata/apply-local-val/outputs.tf delete mode 100644 internal/terraform/testdata/apply-map-var-through-module/amodule/main.tf delete mode 100644 internal/terraform/testdata/apply-map-var-through-module/main.tf delete mode 100644 internal/terraform/testdata/apply-minimal/main.tf delete mode 100644 internal/terraform/testdata/apply-module-bool/child/main.tf delete mode 100644 internal/terraform/testdata/apply-module-bool/main.tf delete mode 100644 internal/terraform/testdata/apply-module-depends-on/main.tf delete mode 100644 internal/terraform/testdata/apply-module-depends-on/moda/main.tf delete mode 100644 internal/terraform/testdata/apply-module-depends-on/modb/main.tf delete mode 100644 internal/terraform/testdata/apply-module-destroy-order/child/main.tf delete mode 100644 internal/terraform/testdata/apply-module-destroy-order/main.tf delete mode 100644 internal/terraform/testdata/apply-module-grandchild-provider-inherit/child/grandchild/main.tf delete mode 100644 internal/terraform/testdata/apply-module-grandchild-provider-inherit/child/main.tf delete mode 100644 internal/terraform/testdata/apply-module-grandchild-provider-inherit/main.tf delete mode 100644 internal/terraform/testdata/apply-module-only-provider/child/main.tf delete mode 100644 internal/terraform/testdata/apply-module-only-provider/main.tf delete mode 100644 internal/terraform/testdata/apply-module-orphan-provider-inherit/main.tf delete mode 100644 internal/terraform/testdata/apply-module-provider-alias/child/main.tf delete mode 100644 internal/terraform/testdata/apply-module-provider-alias/main.tf delete mode 100644 internal/terraform/testdata/apply-module-provider-close-nested/child/main.tf delete mode 100644 internal/terraform/testdata/apply-module-provider-close-nested/child/subchild/main.tf delete mode 100644 internal/terraform/testdata/apply-module-provider-close-nested/main.tf delete mode 100644 internal/terraform/testdata/apply-module-provider-inherit-alias-orphan/main.tf delete mode 100644 internal/terraform/testdata/apply-module-provider-inherit-alias/child/main.tf delete mode 100644 internal/terraform/testdata/apply-module-provider-inherit-alias/main.tf delete mode 100644 internal/terraform/testdata/apply-module-replace-cycle-cbd/main.tf delete mode 100644 internal/terraform/testdata/apply-module-replace-cycle-cbd/mod1/main.tf delete mode 100644 internal/terraform/testdata/apply-module-replace-cycle-cbd/mod2/main.tf delete mode 100644 internal/terraform/testdata/apply-module-replace-cycle/main.tf delete mode 100644 internal/terraform/testdata/apply-module-replace-cycle/mod1/main.tf delete mode 100644 internal/terraform/testdata/apply-module-replace-cycle/mod2/main.tf delete mode 100644 internal/terraform/testdata/apply-module-var-resource-count/child/main.tf delete mode 100644 internal/terraform/testdata/apply-module-var-resource-count/main.tf delete mode 100644 internal/terraform/testdata/apply-module/child/main.tf delete mode 100644 internal/terraform/testdata/apply-module/main.tf delete mode 100644 internal/terraform/testdata/apply-multi-depose-create-before-destroy/main.tf delete mode 100644 internal/terraform/testdata/apply-multi-provider-destroy-child/child/main.tf delete mode 100644 internal/terraform/testdata/apply-multi-provider-destroy-child/main.tf delete mode 100644 internal/terraform/testdata/apply-multi-provider-destroy/main.tf delete mode 100644 internal/terraform/testdata/apply-multi-provider/main.tf delete mode 100644 internal/terraform/testdata/apply-multi-ref/main.tf delete mode 100644 internal/terraform/testdata/apply-multi-var-comprehensive/child/child.tf delete mode 100644 internal/terraform/testdata/apply-multi-var-comprehensive/root.tf delete mode 100644 internal/terraform/testdata/apply-multi-var-count-dec/main.tf delete mode 100644 internal/terraform/testdata/apply-multi-var-missing-state/child/child.tf delete mode 100644 internal/terraform/testdata/apply-multi-var-missing-state/root.tf delete mode 100644 internal/terraform/testdata/apply-multi-var-order-interp/main.tf delete mode 100644 internal/terraform/testdata/apply-multi-var-order/main.tf delete mode 100644 internal/terraform/testdata/apply-multi-var/main.tf delete mode 100644 internal/terraform/testdata/apply-nullable-variables/main.tf delete mode 100644 internal/terraform/testdata/apply-nullable-variables/mod/main.tf delete mode 100644 internal/terraform/testdata/apply-orphan-resource/main.tf delete mode 100644 internal/terraform/testdata/apply-output-add-after/main.tf delete mode 100644 internal/terraform/testdata/apply-output-add-after/outputs.tf.json delete mode 100644 internal/terraform/testdata/apply-output-add-before/main.tf delete mode 100644 internal/terraform/testdata/apply-output-add-before/outputs.tf.json delete mode 100644 internal/terraform/testdata/apply-output-list/main.tf delete mode 100644 internal/terraform/testdata/apply-output-multi-index/main.tf delete mode 100644 internal/terraform/testdata/apply-output-multi/main.tf delete mode 100644 internal/terraform/testdata/apply-output-orphan-module/child/main.tf delete mode 100644 internal/terraform/testdata/apply-output-orphan-module/main.tf delete mode 100644 internal/terraform/testdata/apply-output-orphan/main.tf delete mode 100644 internal/terraform/testdata/apply-output/main.tf delete mode 100644 internal/terraform/testdata/apply-plan-connection-refs/main.tf delete mode 100644 internal/terraform/testdata/apply-provider-alias-configure/main.tf delete mode 100644 internal/terraform/testdata/apply-provider-alias/main.tf delete mode 100644 internal/terraform/testdata/apply-provider-computed/main.tf delete mode 100644 internal/terraform/testdata/apply-provider-configure-disabled/child/main.tf delete mode 100644 internal/terraform/testdata/apply-provider-configure-disabled/main.tf delete mode 100644 internal/terraform/testdata/apply-provider-warning/main.tf delete mode 100644 internal/terraform/testdata/apply-provisioner-compute/main.tf delete mode 100644 internal/terraform/testdata/apply-provisioner-destroy-continue/main.tf delete mode 100644 internal/terraform/testdata/apply-provisioner-destroy-fail/main.tf delete mode 100644 internal/terraform/testdata/apply-provisioner-destroy/main.tf delete mode 100644 internal/terraform/testdata/apply-provisioner-diff/main.tf delete mode 100644 internal/terraform/testdata/apply-provisioner-explicit-self-ref/main.tf delete mode 100644 internal/terraform/testdata/apply-provisioner-fail-continue/main.tf delete mode 100644 internal/terraform/testdata/apply-provisioner-fail-create-before/main.tf delete mode 100644 internal/terraform/testdata/apply-provisioner-fail-create/main.tf delete mode 100644 internal/terraform/testdata/apply-provisioner-fail/main.tf delete mode 100644 internal/terraform/testdata/apply-provisioner-for-each-self/main.tf delete mode 100644 internal/terraform/testdata/apply-provisioner-interp-count/provisioner-interp-count.tf delete mode 100644 internal/terraform/testdata/apply-provisioner-module/child/main.tf delete mode 100644 internal/terraform/testdata/apply-provisioner-module/main.tf delete mode 100644 internal/terraform/testdata/apply-provisioner-multi-self-ref-single/main.tf delete mode 100644 internal/terraform/testdata/apply-provisioner-multi-self-ref/main.tf delete mode 100644 internal/terraform/testdata/apply-provisioner-resource-ref/main.tf delete mode 100644 internal/terraform/testdata/apply-provisioner-self-ref/main.tf delete mode 100644 internal/terraform/testdata/apply-provisioner-sensitive/main.tf delete mode 100644 internal/terraform/testdata/apply-ref-count/main.tf delete mode 100644 internal/terraform/testdata/apply-ref-existing/child/main.tf delete mode 100644 internal/terraform/testdata/apply-ref-existing/main.tf delete mode 100644 internal/terraform/testdata/apply-resource-count-one-list/main.tf delete mode 100644 internal/terraform/testdata/apply-resource-count-zero-list/main.tf delete mode 100644 internal/terraform/testdata/apply-resource-depends-on-module-deep/child/child/main.tf delete mode 100644 internal/terraform/testdata/apply-resource-depends-on-module-deep/child/main.tf delete mode 100644 internal/terraform/testdata/apply-resource-depends-on-module-deep/main.tf delete mode 100644 internal/terraform/testdata/apply-resource-depends-on-module-empty/main.tf delete mode 100644 internal/terraform/testdata/apply-resource-depends-on-module-in-module/child/child/main.tf delete mode 100644 internal/terraform/testdata/apply-resource-depends-on-module-in-module/child/main.tf delete mode 100644 internal/terraform/testdata/apply-resource-depends-on-module-in-module/main.tf delete mode 100644 internal/terraform/testdata/apply-resource-depends-on-module/child/main.tf delete mode 100644 internal/terraform/testdata/apply-resource-depends-on-module/main.tf delete mode 100644 internal/terraform/testdata/apply-resource-scale-in/main.tf delete mode 100644 internal/terraform/testdata/apply-taint-dep-requires-new/main.tf delete mode 100644 internal/terraform/testdata/apply-taint-dep/main.tf delete mode 100644 internal/terraform/testdata/apply-taint/main.tf delete mode 100644 internal/terraform/testdata/apply-tainted-targets/main.tf delete mode 100644 internal/terraform/testdata/apply-targeted-count/main.tf delete mode 100644 internal/terraform/testdata/apply-targeted-module-dep/child/main.tf delete mode 100644 internal/terraform/testdata/apply-targeted-module-dep/main.tf delete mode 100644 internal/terraform/testdata/apply-targeted-module-recursive/child/main.tf delete mode 100644 internal/terraform/testdata/apply-targeted-module-recursive/child/subchild/main.tf delete mode 100644 internal/terraform/testdata/apply-targeted-module-recursive/main.tf delete mode 100644 internal/terraform/testdata/apply-targeted-module-resource/child/main.tf delete mode 100644 internal/terraform/testdata/apply-targeted-module-resource/main.tf delete mode 100644 internal/terraform/testdata/apply-targeted-module-unrelated-outputs/child1/main.tf delete mode 100644 internal/terraform/testdata/apply-targeted-module-unrelated-outputs/child2/main.tf delete mode 100644 internal/terraform/testdata/apply-targeted-module-unrelated-outputs/main.tf delete mode 100644 internal/terraform/testdata/apply-targeted-module/child/main.tf delete mode 100644 internal/terraform/testdata/apply-targeted-module/main.tf delete mode 100644 internal/terraform/testdata/apply-targeted-resource-orphan-module/child/main.tf delete mode 100644 internal/terraform/testdata/apply-targeted-resource-orphan-module/main.tf delete mode 100644 internal/terraform/testdata/apply-targeted/main.tf delete mode 100644 internal/terraform/testdata/apply-terraform-workspace/main.tf delete mode 100644 internal/terraform/testdata/apply-unknown-interpolate/child/main.tf delete mode 100644 internal/terraform/testdata/apply-unknown-interpolate/main.tf delete mode 100644 internal/terraform/testdata/apply-unknown/main.tf delete mode 100644 internal/terraform/testdata/apply-unstable/main.tf delete mode 100644 internal/terraform/testdata/apply-vars-env/main.tf delete mode 100644 internal/terraform/testdata/apply-vars/main.tf delete mode 100644 internal/terraform/testdata/context-required-version-module/child/main.tf delete mode 100644 internal/terraform/testdata/context-required-version-module/main.tf delete mode 100644 internal/terraform/testdata/context-required-version/main.tf delete mode 100644 internal/terraform/testdata/data-source-read-with-plan-error/main.tf delete mode 100644 internal/terraform/testdata/destroy-module-with-provider/main.tf delete mode 100644 internal/terraform/testdata/destroy-module-with-provider/mod/main.tf delete mode 100644 internal/terraform/testdata/destroy-targeted/child/main.tf delete mode 100644 internal/terraform/testdata/destroy-targeted/main.tf delete mode 100644 internal/terraform/testdata/empty/main.tf delete mode 100644 internal/terraform/testdata/eval-context-basic/child/main.tf delete mode 100644 internal/terraform/testdata/eval-context-basic/main.tf delete mode 100644 internal/terraform/testdata/graph-basic/main.tf delete mode 100644 internal/terraform/testdata/graph-builder-apply-basic/child/main.tf delete mode 100644 internal/terraform/testdata/graph-builder-apply-basic/main.tf delete mode 100644 internal/terraform/testdata/graph-builder-apply-count/main.tf delete mode 100644 internal/terraform/testdata/graph-builder-apply-dep-cbd/main.tf delete mode 100644 internal/terraform/testdata/graph-builder-apply-double-cbd/main.tf delete mode 100644 internal/terraform/testdata/graph-builder-apply-module-destroy/A/main.tf delete mode 100644 internal/terraform/testdata/graph-builder-apply-module-destroy/main.tf delete mode 100644 internal/terraform/testdata/graph-builder-apply-orphan-update/main.tf delete mode 100644 internal/terraform/testdata/graph-builder-apply-provisioner/main.tf delete mode 100644 internal/terraform/testdata/graph-builder-apply-target-module/child1/main.tf delete mode 100644 internal/terraform/testdata/graph-builder-apply-target-module/child2/main.tf delete mode 100644 internal/terraform/testdata/graph-builder-apply-target-module/main.tf delete mode 100644 internal/terraform/testdata/graph-builder-orphan-alias/main.tf delete mode 100644 internal/terraform/testdata/graph-builder-plan-attr-as-blocks/attr-as-blocks.tf delete mode 100644 internal/terraform/testdata/graph-builder-plan-basic/main.tf delete mode 100644 internal/terraform/testdata/graph-builder-plan-dynblock/dynblock.tf delete mode 100644 internal/terraform/testdata/graph-builder-plan-target-module-provider/child1/main.tf delete mode 100644 internal/terraform/testdata/graph-builder-plan-target-module-provider/child2/main.tf delete mode 100644 internal/terraform/testdata/graph-builder-plan-target-module-provider/main.tf delete mode 100644 internal/terraform/testdata/import-module/child/main.tf delete mode 100644 internal/terraform/testdata/import-module/child/submodule/main.tf delete mode 100644 internal/terraform/testdata/import-module/main.tf delete mode 100644 internal/terraform/testdata/import-provider-locals/main.tf delete mode 100644 internal/terraform/testdata/import-provider-resources/main.tf delete mode 100644 internal/terraform/testdata/import-provider-vars/main.tf delete mode 100644 internal/terraform/testdata/import-provider/main.tf delete mode 100644 internal/terraform/testdata/input-interpolate-var/child/main.tf delete mode 100644 internal/terraform/testdata/input-interpolate-var/main.tf delete mode 100644 internal/terraform/testdata/input-interpolate-var/source/main.tf delete mode 100644 internal/terraform/testdata/input-module-data-vars/child/main.tf delete mode 100644 internal/terraform/testdata/input-module-data-vars/main.tf delete mode 100644 internal/terraform/testdata/input-provider-multi/main.tf delete mode 100644 internal/terraform/testdata/input-provider-once/child/main.tf delete mode 100644 internal/terraform/testdata/input-provider-once/main.tf delete mode 100644 internal/terraform/testdata/input-provider-vars/main.tf delete mode 100644 internal/terraform/testdata/input-provider-with-vars-and-module/child/main.tf delete mode 100644 internal/terraform/testdata/input-provider-with-vars-and-module/main.tf delete mode 100644 internal/terraform/testdata/input-provider-with-vars/main.tf delete mode 100644 internal/terraform/testdata/input-provider/main.tf delete mode 100644 internal/terraform/testdata/input-submodule-count/main.tf delete mode 100644 internal/terraform/testdata/input-submodule-count/mod/main.tf delete mode 100644 internal/terraform/testdata/input-submodule-count/mod/submod/main.tf delete mode 100644 internal/terraform/testdata/input-variables/main.tf delete mode 100644 internal/terraform/testdata/issue-5254/step-0/main.tf delete mode 100644 internal/terraform/testdata/issue-5254/step-1/main.tf delete mode 100644 internal/terraform/testdata/issue-7824/main.tf delete mode 100644 internal/terraform/testdata/issue-9549/main.tf delete mode 100644 internal/terraform/testdata/issue-9549/mod/main.tf delete mode 100644 internal/terraform/testdata/nested-resource-count-plan/main.tf delete mode 100644 internal/terraform/testdata/plan-block-nesting-group/block-nesting-group.tf delete mode 100644 internal/terraform/testdata/plan-cbd-depends-datasource/main.tf delete mode 100644 internal/terraform/testdata/plan-cbd-maintain-root/main.tf delete mode 100644 internal/terraform/testdata/plan-cbd/main.tf delete mode 100644 internal/terraform/testdata/plan-close-module-provider/main.tf delete mode 100644 internal/terraform/testdata/plan-close-module-provider/mod/main.tf delete mode 100644 internal/terraform/testdata/plan-computed-attr-ref-type-mismatch/main.tf delete mode 100644 internal/terraform/testdata/plan-computed-data-count/main.tf delete mode 100644 internal/terraform/testdata/plan-computed-data-resource/main.tf delete mode 100644 internal/terraform/testdata/plan-computed-in-function/main.tf delete mode 100644 internal/terraform/testdata/plan-computed-list/main.tf delete mode 100644 internal/terraform/testdata/plan-computed-multi-index/main.tf delete mode 100644 internal/terraform/testdata/plan-computed-value-in-map/main.tf delete mode 100644 internal/terraform/testdata/plan-computed-value-in-map/mod/main.tf delete mode 100644 internal/terraform/testdata/plan-computed/main.tf delete mode 100644 internal/terraform/testdata/plan-count-computed-module/child/main.tf delete mode 100644 internal/terraform/testdata/plan-count-computed-module/main.tf delete mode 100644 internal/terraform/testdata/plan-count-computed/main.tf delete mode 100644 internal/terraform/testdata/plan-count-dec/main.tf delete mode 100644 internal/terraform/testdata/plan-count-inc/main.tf delete mode 100644 internal/terraform/testdata/plan-count-index/main.tf delete mode 100644 internal/terraform/testdata/plan-count-module-static-grandchild/child/child/main.tf delete mode 100644 internal/terraform/testdata/plan-count-module-static-grandchild/child/main.tf delete mode 100644 internal/terraform/testdata/plan-count-module-static-grandchild/main.tf delete mode 100644 internal/terraform/testdata/plan-count-module-static/child/main.tf delete mode 100644 internal/terraform/testdata/plan-count-module-static/main.tf delete mode 100644 internal/terraform/testdata/plan-count-one-index/main.tf delete mode 100644 internal/terraform/testdata/plan-count-splat-reference/main.tf delete mode 100644 internal/terraform/testdata/plan-count-var/main.tf delete mode 100644 internal/terraform/testdata/plan-count-zero/main.tf delete mode 100644 internal/terraform/testdata/plan-count/main.tf delete mode 100644 internal/terraform/testdata/plan-data-depends-on/main.tf delete mode 100644 internal/terraform/testdata/plan-data-resource-becomes-computed/main.tf delete mode 100644 internal/terraform/testdata/plan-destroy-interpolated-count/main.tf delete mode 100644 internal/terraform/testdata/plan-destroy-interpolated-count/mod/main.tf delete mode 100644 internal/terraform/testdata/plan-destroy/main.tf delete mode 100644 internal/terraform/testdata/plan-diffvar/main.tf delete mode 100644 internal/terraform/testdata/plan-empty/main.tf delete mode 100644 internal/terraform/testdata/plan-escaped-var/main.tf delete mode 100644 internal/terraform/testdata/plan-for-each-unknown-value/main.tf delete mode 100644 internal/terraform/testdata/plan-for-each/main.tf delete mode 100644 internal/terraform/testdata/plan-good/main.tf delete mode 100644 internal/terraform/testdata/plan-ignore-changes-in-map/ignore-changes-in-map.tf delete mode 100644 internal/terraform/testdata/plan-ignore-changes-sensitive/ignore-changes-sensitive.tf delete mode 100644 internal/terraform/testdata/plan-ignore-changes-wildcard/main.tf delete mode 100644 internal/terraform/testdata/plan-ignore-changes-with-flatmaps/main.tf delete mode 100644 internal/terraform/testdata/plan-ignore-changes/main.tf delete mode 100644 internal/terraform/testdata/plan-list-order/main.tf delete mode 100644 internal/terraform/testdata/plan-local-value-count/main.tf delete mode 100644 internal/terraform/testdata/plan-module-cycle/child/main.tf delete mode 100644 internal/terraform/testdata/plan-module-cycle/main.tf delete mode 100644 internal/terraform/testdata/plan-module-deadlock/child/main.tf delete mode 100644 internal/terraform/testdata/plan-module-deadlock/main.tf delete mode 100644 internal/terraform/testdata/plan-module-destroy-gh-1835/a/main.tf delete mode 100644 internal/terraform/testdata/plan-module-destroy-gh-1835/b/main.tf delete mode 100644 internal/terraform/testdata/plan-module-destroy-gh-1835/main.tf delete mode 100644 internal/terraform/testdata/plan-module-destroy-multivar/child/main.tf delete mode 100644 internal/terraform/testdata/plan-module-destroy-multivar/main.tf delete mode 100644 internal/terraform/testdata/plan-module-destroy/child/main.tf delete mode 100644 internal/terraform/testdata/plan-module-destroy/main.tf delete mode 100644 internal/terraform/testdata/plan-module-input-computed/child/main.tf delete mode 100644 internal/terraform/testdata/plan-module-input-computed/main.tf delete mode 100644 internal/terraform/testdata/plan-module-input-var/child/main.tf delete mode 100644 internal/terraform/testdata/plan-module-input-var/main.tf delete mode 100644 internal/terraform/testdata/plan-module-input/child/main.tf delete mode 100644 internal/terraform/testdata/plan-module-input/main.tf delete mode 100644 internal/terraform/testdata/plan-module-map-literal/child/main.tf delete mode 100644 internal/terraform/testdata/plan-module-map-literal/main.tf delete mode 100644 internal/terraform/testdata/plan-module-multi-var/child/main.tf delete mode 100644 internal/terraform/testdata/plan-module-multi-var/main.tf delete mode 100644 internal/terraform/testdata/plan-module-provider-defaults-var/child/main.tf delete mode 100644 internal/terraform/testdata/plan-module-provider-defaults-var/main.tf delete mode 100644 internal/terraform/testdata/plan-module-provider-defaults/child/main.tf delete mode 100644 internal/terraform/testdata/plan-module-provider-defaults/main.tf delete mode 100644 internal/terraform/testdata/plan-module-provider-inherit-deep/A/main.tf delete mode 100644 internal/terraform/testdata/plan-module-provider-inherit-deep/B/main.tf delete mode 100644 internal/terraform/testdata/plan-module-provider-inherit-deep/C/main.tf delete mode 100644 internal/terraform/testdata/plan-module-provider-inherit-deep/main.tf delete mode 100644 internal/terraform/testdata/plan-module-provider-inherit/child/main.tf delete mode 100644 internal/terraform/testdata/plan-module-provider-inherit/main.tf delete mode 100644 internal/terraform/testdata/plan-module-provider-var/child/main.tf delete mode 100644 internal/terraform/testdata/plan-module-provider-var/main.tf delete mode 100644 internal/terraform/testdata/plan-module-var-computed/child/main.tf delete mode 100644 internal/terraform/testdata/plan-module-var-computed/main.tf delete mode 100644 internal/terraform/testdata/plan-module-var-with-default-value/inner/main.tf delete mode 100644 internal/terraform/testdata/plan-module-var-with-default-value/main.tf delete mode 100644 internal/terraform/testdata/plan-module-var/child/main.tf delete mode 100644 internal/terraform/testdata/plan-module-var/main.tf delete mode 100644 internal/terraform/testdata/plan-module-variable-from-splat/main.tf delete mode 100644 internal/terraform/testdata/plan-module-variable-from-splat/mod/main.tf delete mode 100644 internal/terraform/testdata/plan-module-wrong-var-type-nested/inner/main.tf delete mode 100644 internal/terraform/testdata/plan-module-wrong-var-type-nested/main.tf delete mode 100644 internal/terraform/testdata/plan-module-wrong-var-type-nested/middle/main.tf delete mode 100644 internal/terraform/testdata/plan-module-wrong-var-type/inner/main.tf delete mode 100644 internal/terraform/testdata/plan-module-wrong-var-type/main.tf delete mode 100644 internal/terraform/testdata/plan-modules-expand/child/main.tf delete mode 100644 internal/terraform/testdata/plan-modules-expand/main.tf delete mode 100644 internal/terraform/testdata/plan-modules-remove-provisioners/main.tf delete mode 100644 internal/terraform/testdata/plan-modules-remove-provisioners/parent/child/main.tf delete mode 100644 internal/terraform/testdata/plan-modules-remove-provisioners/parent/main.tf delete mode 100644 internal/terraform/testdata/plan-modules-remove/main.tf delete mode 100644 internal/terraform/testdata/plan-modules/child/main.tf delete mode 100644 internal/terraform/testdata/plan-modules/main.tf delete mode 100644 internal/terraform/testdata/plan-orphan/main.tf delete mode 100644 internal/terraform/testdata/plan-path-var/main.tf delete mode 100644 internal/terraform/testdata/plan-prevent-destroy-bad/main.tf delete mode 100644 internal/terraform/testdata/plan-prevent-destroy-count-bad/main.tf delete mode 100644 internal/terraform/testdata/plan-prevent-destroy-count-good/main.tf delete mode 100644 internal/terraform/testdata/plan-prevent-destroy-good/main.tf delete mode 100644 internal/terraform/testdata/plan-provider/main.tf delete mode 100644 internal/terraform/testdata/plan-provisioner-cycle/main.tf delete mode 100644 internal/terraform/testdata/plan-required-output/main.tf delete mode 100644 internal/terraform/testdata/plan-required-output/mod/main.tf delete mode 100644 internal/terraform/testdata/plan-required-whole-mod/main.tf delete mode 100644 internal/terraform/testdata/plan-required-whole-mod/mod/main.tf delete mode 100644 internal/terraform/testdata/plan-requires-replace/main.tf delete mode 100644 internal/terraform/testdata/plan-self-ref-multi-all/main.tf delete mode 100644 internal/terraform/testdata/plan-self-ref-multi/main.tf delete mode 100644 internal/terraform/testdata/plan-self-ref/main.tf delete mode 100644 internal/terraform/testdata/plan-shadow-uuid/main.tf delete mode 100644 internal/terraform/testdata/plan-taint-ignore-changes/main.tf delete mode 100644 internal/terraform/testdata/plan-taint-interpolated-count/main.tf delete mode 100644 internal/terraform/testdata/plan-taint/main.tf delete mode 100644 internal/terraform/testdata/plan-targeted-cross-module/A/main.tf delete mode 100644 internal/terraform/testdata/plan-targeted-cross-module/B/main.tf delete mode 100644 internal/terraform/testdata/plan-targeted-cross-module/main.tf delete mode 100644 internal/terraform/testdata/plan-targeted-module-orphan/main.tf delete mode 100644 internal/terraform/testdata/plan-targeted-module-untargeted-variable/child/main.tf delete mode 100644 internal/terraform/testdata/plan-targeted-module-untargeted-variable/main.tf delete mode 100644 internal/terraform/testdata/plan-targeted-module-with-provider/child1/main.tf delete mode 100644 internal/terraform/testdata/plan-targeted-module-with-provider/child2/main.tf delete mode 100644 internal/terraform/testdata/plan-targeted-module-with-provider/main.tf delete mode 100644 internal/terraform/testdata/plan-targeted-orphan/main.tf delete mode 100644 internal/terraform/testdata/plan-targeted-over-ten/main.tf delete mode 100644 internal/terraform/testdata/plan-targeted/main.tf delete mode 100644 internal/terraform/testdata/plan-targeted/mod/main.tf delete mode 100644 internal/terraform/testdata/plan-untargeted-resource-output/main.tf delete mode 100644 internal/terraform/testdata/plan-untargeted-resource-output/mod/main.tf delete mode 100644 internal/terraform/testdata/plan-var-list-err/main.tf delete mode 100644 internal/terraform/testdata/plan-variable-sensitivity-module/child/main.tf delete mode 100644 internal/terraform/testdata/plan-variable-sensitivity-module/main.tf delete mode 100644 internal/terraform/testdata/plan-variable-sensitivity/main.tf delete mode 100644 internal/terraform/testdata/provider-meta-data-set/main.tf delete mode 100644 internal/terraform/testdata/provider-meta-data-set/my-module/main.tf delete mode 100644 internal/terraform/testdata/provider-meta-data-unset/main.tf delete mode 100644 internal/terraform/testdata/provider-meta-data-unset/my-module/main.tf delete mode 100644 internal/terraform/testdata/provider-meta-set/main.tf delete mode 100644 internal/terraform/testdata/provider-meta-set/my-module/main.tf delete mode 100644 internal/terraform/testdata/provider-meta-unset/main.tf delete mode 100644 internal/terraform/testdata/provider-meta-unset/my-module/main.tf delete mode 100644 internal/terraform/testdata/provider-with-locals/main.tf delete mode 100644 internal/terraform/testdata/refresh-basic/main.tf delete mode 100644 internal/terraform/testdata/refresh-data-count/refresh-data-count.tf delete mode 100644 internal/terraform/testdata/refresh-data-module-var/child/main.tf delete mode 100644 internal/terraform/testdata/refresh-data-module-var/main.tf delete mode 100644 internal/terraform/testdata/refresh-data-ref-data/main.tf delete mode 100644 internal/terraform/testdata/refresh-data-resource-basic/main.tf delete mode 100644 internal/terraform/testdata/refresh-dynamic/main.tf delete mode 100644 internal/terraform/testdata/refresh-module-computed-var/child/main.tf delete mode 100644 internal/terraform/testdata/refresh-module-computed-var/main.tf delete mode 100644 internal/terraform/testdata/refresh-module-input-computed-output/child/main.tf delete mode 100644 internal/terraform/testdata/refresh-module-input-computed-output/main.tf delete mode 100644 internal/terraform/testdata/refresh-module-orphan/child/grandchild/main.tf delete mode 100644 internal/terraform/testdata/refresh-module-orphan/child/main.tf delete mode 100644 internal/terraform/testdata/refresh-module-orphan/main.tf delete mode 100644 internal/terraform/testdata/refresh-module-var-module/bar/main.tf delete mode 100644 internal/terraform/testdata/refresh-module-var-module/foo/main.tf delete mode 100644 internal/terraform/testdata/refresh-module-var-module/main.tf delete mode 100644 internal/terraform/testdata/refresh-modules/child/main.tf delete mode 100644 internal/terraform/testdata/refresh-modules/main.tf delete mode 100644 internal/terraform/testdata/refresh-no-state/main.tf delete mode 100644 internal/terraform/testdata/refresh-output-partial/main.tf delete mode 100644 internal/terraform/testdata/refresh-output/main.tf delete mode 100644 internal/terraform/testdata/refresh-schema-upgrade/main.tf delete mode 100644 internal/terraform/testdata/refresh-targeted-count/main.tf delete mode 100644 internal/terraform/testdata/refresh-targeted/main.tf delete mode 100644 internal/terraform/testdata/refresh-unknown-provider/main.tf delete mode 100644 internal/terraform/testdata/refresh-vars/main.tf delete mode 100644 internal/terraform/testdata/static-validate-refs/static-validate-refs.tf delete mode 100644 internal/terraform/testdata/transform-cbd-destroy-edge-both-count/main.tf delete mode 100644 internal/terraform/testdata/transform-cbd-destroy-edge-count/main.tf delete mode 100644 internal/terraform/testdata/transform-config-mode-data/main.tf delete mode 100644 internal/terraform/testdata/transform-destroy-cbd-edge-basic/main.tf delete mode 100644 internal/terraform/testdata/transform-destroy-cbd-edge-multi/main.tf delete mode 100644 internal/terraform/testdata/transform-destroy-edge-basic/main.tf delete mode 100644 internal/terraform/testdata/transform-destroy-edge-module-only/child/main.tf delete mode 100644 internal/terraform/testdata/transform-destroy-edge-module-only/main.tf delete mode 100644 internal/terraform/testdata/transform-destroy-edge-module/child/main.tf delete mode 100644 internal/terraform/testdata/transform-destroy-edge-module/main.tf delete mode 100644 internal/terraform/testdata/transform-destroy-edge-multi/main.tf delete mode 100644 internal/terraform/testdata/transform-destroy-edge-self-ref/main.tf delete mode 100644 internal/terraform/testdata/transform-module-var-basic/child/main.tf delete mode 100644 internal/terraform/testdata/transform-module-var-basic/main.tf delete mode 100644 internal/terraform/testdata/transform-module-var-nested/child/child/main.tf delete mode 100644 internal/terraform/testdata/transform-module-var-nested/child/main.tf delete mode 100644 internal/terraform/testdata/transform-module-var-nested/main.tf delete mode 100644 internal/terraform/testdata/transform-orphan-basic/main.tf delete mode 100644 internal/terraform/testdata/transform-orphan-count-empty/main.tf delete mode 100644 internal/terraform/testdata/transform-orphan-count/main.tf delete mode 100644 internal/terraform/testdata/transform-orphan-modules/main.tf delete mode 100644 internal/terraform/testdata/transform-provider-basic/main.tf delete mode 100644 internal/terraform/testdata/transform-provider-fqns-module/child/main.tf delete mode 100644 internal/terraform/testdata/transform-provider-fqns-module/main.tf delete mode 100644 internal/terraform/testdata/transform-provider-fqns/main.tf delete mode 100644 internal/terraform/testdata/transform-provider-grandchild-inherit/child/grandchild/main.tf delete mode 100644 internal/terraform/testdata/transform-provider-grandchild-inherit/child/main.tf delete mode 100644 internal/terraform/testdata/transform-provider-grandchild-inherit/main.tf delete mode 100644 internal/terraform/testdata/transform-provider-inherit/child/main.tf delete mode 100644 internal/terraform/testdata/transform-provider-inherit/main.tf delete mode 100644 internal/terraform/testdata/transform-provider-missing-grandchild/main.tf delete mode 100644 internal/terraform/testdata/transform-provider-missing-grandchild/sub/main.tf delete mode 100644 internal/terraform/testdata/transform-provider-missing-grandchild/sub/subsub/main.tf delete mode 100644 internal/terraform/testdata/transform-provider-missing/main.tf delete mode 100644 internal/terraform/testdata/transform-provider-prune/main.tf delete mode 100644 internal/terraform/testdata/transform-provisioner-basic/main.tf delete mode 100644 internal/terraform/testdata/transform-provisioner-module/child/main.tf delete mode 100644 internal/terraform/testdata/transform-provisioner-module/main.tf delete mode 100644 internal/terraform/testdata/transform-root-basic/main.tf delete mode 100644 internal/terraform/testdata/transform-targets-basic/main.tf delete mode 100644 internal/terraform/testdata/transform-targets-downstream/child/child.tf delete mode 100644 internal/terraform/testdata/transform-targets-downstream/child/grandchild/grandchild.tf delete mode 100644 internal/terraform/testdata/transform-targets-downstream/main.tf delete mode 100644 internal/terraform/testdata/transform-trans-reduce-basic/main.tf delete mode 100644 internal/terraform/testdata/update-resource-provider/main.tf delete mode 100644 internal/terraform/testdata/validate-bad-count/main.tf delete mode 100644 internal/terraform/testdata/validate-bad-module-output/child/main.tf delete mode 100644 internal/terraform/testdata/validate-bad-module-output/main.tf delete mode 100644 internal/terraform/testdata/validate-bad-pc/main.tf delete mode 100644 internal/terraform/testdata/validate-bad-prov-conf/main.tf delete mode 100644 internal/terraform/testdata/validate-bad-prov-connection/main.tf delete mode 100644 internal/terraform/testdata/validate-bad-rc/main.tf delete mode 100644 internal/terraform/testdata/validate-bad-resource-connection/main.tf delete mode 100644 internal/terraform/testdata/validate-bad-resource-count/main.tf delete mode 100644 internal/terraform/testdata/validate-bad-var/main.tf delete mode 100644 internal/terraform/testdata/validate-computed-in-function/main.tf delete mode 100644 internal/terraform/testdata/validate-computed-module-var-ref/dest/main.tf delete mode 100644 internal/terraform/testdata/validate-computed-module-var-ref/main.tf delete mode 100644 internal/terraform/testdata/validate-computed-module-var-ref/source/main.tf delete mode 100644 internal/terraform/testdata/validate-computed-var/main.tf delete mode 100644 internal/terraform/testdata/validate-count-computed/main.tf delete mode 100644 internal/terraform/testdata/validate-count-negative/main.tf delete mode 100644 internal/terraform/testdata/validate-count-variable/main.tf delete mode 100644 internal/terraform/testdata/validate-good-module/child/main.tf delete mode 100644 internal/terraform/testdata/validate-good-module/main.tf delete mode 100644 internal/terraform/testdata/validate-good/main.tf delete mode 100644 internal/terraform/testdata/validate-module-bad-rc/child/main.tf delete mode 100644 internal/terraform/testdata/validate-module-bad-rc/main.tf delete mode 100644 internal/terraform/testdata/validate-module-deps-cycle/a/main.tf delete mode 100644 internal/terraform/testdata/validate-module-deps-cycle/b/main.tf delete mode 100644 internal/terraform/testdata/validate-module-deps-cycle/main.tf delete mode 100644 internal/terraform/testdata/validate-module-pc-inherit-unused/child/main.tf delete mode 100644 internal/terraform/testdata/validate-module-pc-inherit-unused/main.tf delete mode 100644 internal/terraform/testdata/validate-module-pc-inherit/child/main.tf delete mode 100644 internal/terraform/testdata/validate-module-pc-inherit/main.tf delete mode 100644 internal/terraform/testdata/validate-module-pc-vars/child/main.tf delete mode 100644 internal/terraform/testdata/validate-module-pc-vars/main.tf delete mode 100644 internal/terraform/testdata/validate-required-provider-config/main.tf delete mode 100644 internal/terraform/testdata/validate-required-var/main.tf delete mode 100644 internal/terraform/testdata/validate-sensitive-provisioner-config/main.tf delete mode 100644 internal/terraform/testdata/validate-skipped-pc-empty/main.tf delete mode 100644 internal/terraform/testdata/validate-targeted/main.tf delete mode 100644 internal/terraform/testdata/validate-var-no-default-explicit-type/main.tf delete mode 100644 internal/terraform/testdata/validate-variable-custom-validations-child-sensitive/child/child.tf delete mode 100644 internal/terraform/testdata/validate-variable-custom-validations-child-sensitive/validate-variable-custom-validations.tf delete mode 100644 internal/terraform/testdata/validate-variable-custom-validations-child/child/child.tf delete mode 100644 internal/terraform/testdata/validate-variable-custom-validations-child/validate-variable-custom-validations.tf delete mode 100644 internal/terraform/testdata/validate-variable-ref/main.tf delete mode 100644 internal/terraform/testdata/vars-basic-bool/main.tf delete mode 100644 internal/terraform/testdata/vars-basic/main.tf delete mode 100644 internal/terraform/transform.go delete mode 100644 internal/terraform/transform_attach_config_provider.go delete mode 100644 internal/terraform/transform_attach_config_provider_meta.go delete mode 100644 internal/terraform/transform_attach_config_resource.go delete mode 100644 internal/terraform/transform_attach_schema.go delete mode 100644 internal/terraform/transform_attach_state.go delete mode 100644 internal/terraform/transform_config.go delete mode 100644 internal/terraform/transform_config_test.go delete mode 100644 internal/terraform/transform_destroy_cbd.go delete mode 100644 internal/terraform/transform_destroy_cbd_test.go delete mode 100644 internal/terraform/transform_destroy_edge.go delete mode 100644 internal/terraform/transform_destroy_edge_test.go delete mode 100644 internal/terraform/transform_diff.go delete mode 100644 internal/terraform/transform_diff_test.go delete mode 100644 internal/terraform/transform_expand.go delete mode 100644 internal/terraform/transform_import_state_test.go delete mode 100644 internal/terraform/transform_local.go delete mode 100644 internal/terraform/transform_module_expansion.go delete mode 100644 internal/terraform/transform_module_variable.go delete mode 100644 internal/terraform/transform_module_variable_test.go delete mode 100644 internal/terraform/transform_orphan_count.go delete mode 100644 internal/terraform/transform_orphan_count_test.go delete mode 100644 internal/terraform/transform_orphan_output.go delete mode 100644 internal/terraform/transform_orphan_resource.go delete mode 100644 internal/terraform/transform_orphan_resource_test.go delete mode 100644 internal/terraform/transform_output.go delete mode 100644 internal/terraform/transform_provider.go delete mode 100644 internal/terraform/transform_provider_test.go delete mode 100644 internal/terraform/transform_provisioner.go delete mode 100644 internal/terraform/transform_reference.go delete mode 100644 internal/terraform/transform_reference_test.go delete mode 100644 internal/terraform/transform_removed_modules.go delete mode 100644 internal/terraform/transform_resource_count.go delete mode 100644 internal/terraform/transform_root.go delete mode 100644 internal/terraform/transform_root_test.go delete mode 100644 internal/terraform/transform_state.go delete mode 100644 internal/terraform/transform_targets.go delete mode 100644 internal/terraform/transform_targets_test.go delete mode 100644 internal/terraform/transform_transitive_reduction.go delete mode 100644 internal/terraform/transform_transitive_reduction_test.go delete mode 100644 internal/terraform/transform_variable.go delete mode 100644 internal/terraform/transform_vertex.go delete mode 100644 internal/terraform/transform_vertex_test.go delete mode 100644 internal/terraform/ui_input.go delete mode 100644 internal/terraform/ui_input_mock.go delete mode 100644 internal/terraform/ui_input_prefix.go delete mode 100644 internal/terraform/ui_input_prefix_test.go delete mode 100644 internal/terraform/ui_output.go delete mode 100644 internal/terraform/ui_output_callback.go delete mode 100644 internal/terraform/ui_output_callback_test.go delete mode 100644 internal/terraform/ui_output_mock.go delete mode 100644 internal/terraform/ui_output_mock_test.go delete mode 100644 internal/terraform/ui_output_provisioner.go delete mode 100644 internal/terraform/ui_output_provisioner_test.go delete mode 100644 internal/terraform/update_state_hook.go delete mode 100644 internal/terraform/update_state_hook_test.go delete mode 100644 internal/terraform/upgrade_resource_state.go delete mode 100644 internal/terraform/upgrade_resource_state_test.go delete mode 100644 internal/terraform/util.go delete mode 100644 internal/terraform/util_test.go delete mode 100644 internal/terraform/validate_selfref.go delete mode 100644 internal/terraform/validate_selfref_test.go delete mode 100644 internal/terraform/valuesourcetype_string.go delete mode 100644 internal/terraform/variables.go delete mode 100644 internal/terraform/variables_test.go delete mode 100644 internal/terraform/version_required.go delete mode 100644 internal/terraform/walkoperation_string.go rename {internal/ipaddr => ipaddr}/LICENSE (100%) rename {internal/ipaddr => ipaddr}/PATENTS (100%) rename {internal/ipaddr => ipaddr}/README.md (100%) rename {internal/ipaddr => ipaddr}/doc.go (100%) rename {internal/ipaddr => ipaddr}/ip.go (100%) rename {internal/ipaddr => ipaddr}/ip_test.go (100%) rename {internal/ipaddr => ipaddr}/parse.go (100%) rename {internal/lang => lang}/blocktoattr/doc.go (100%) rename {internal/lang => lang}/blocktoattr/fixup.go (99%) rename {internal/lang => lang}/blocktoattr/fixup_bench_test.go (97%) rename {internal/lang => lang}/blocktoattr/fixup_test.go (99%) rename {internal/lang => lang}/blocktoattr/schema.go (98%) rename {internal/lang => lang}/blocktoattr/variables.go (97%) rename {internal/lang => lang}/blocktoattr/variables_test.go (98%) rename {internal/lang => lang}/data.go (94%) rename {internal/lang => lang}/data_test.go (95%) rename {internal/lang => lang}/doc.go (100%) rename {internal/lang => lang}/eval.go (98%) rename {internal/lang => lang}/eval_test.go (99%) rename {internal/lang => lang}/funcs/cidr.go (99%) rename {internal/lang => lang}/funcs/cidr_test.go (100%) rename {internal/lang => lang}/funcs/collection.go (100%) rename {internal/lang => lang}/funcs/collection_test.go (99%) rename {internal/lang => lang}/funcs/conversion.go (97%) rename {internal/lang => lang}/funcs/conversion_test.go (98%) rename {internal/lang => lang}/funcs/crypto.go (100%) rename {internal/lang => lang}/funcs/crypto_test.go (100%) rename {internal/lang => lang}/funcs/datetime.go (100%) rename {internal/lang => lang}/funcs/datetime_test.go (100%) rename {internal/lang => lang}/funcs/descriptions.go (100%) rename {internal/lang => lang}/funcs/encoding.go (100%) rename {internal/lang => lang}/funcs/encoding_test.go (99%) rename {internal/lang => lang}/funcs/filesystem.go (100%) rename {internal/lang => lang}/funcs/filesystem_test.go (99%) rename {internal/lang => lang}/funcs/number.go (100%) rename {internal/lang => lang}/funcs/number_test.go (99%) rename {internal/lang => lang}/funcs/redact.go (87%) rename {internal/lang => lang}/funcs/redact_test.go (95%) rename {internal/lang => lang}/funcs/sensitive.go (97%) rename {internal/lang => lang}/funcs/sensitive_test.go (98%) rename {internal/lang => lang}/funcs/string.go (100%) rename {internal/lang => lang}/funcs/string_test.go (100%) rename {internal/lang => lang}/funcs/testdata/bare.tmpl (100%) rename {internal/lang => lang}/funcs/testdata/func.tmpl (100%) rename {internal/lang => lang}/funcs/testdata/hello.tmpl (100%) rename {internal/lang => lang}/funcs/testdata/hello.txt (100%) rename {internal/lang => lang}/funcs/testdata/icon.png (100%) rename {internal/lang => lang}/funcs/testdata/list.tmpl (100%) rename {internal/lang => lang}/funcs/testdata/recursive.tmpl (100%) rename {internal/lang => lang}/funcs/testdata/unreadable/foobar (100%) rename {internal/lang => lang}/functions.go (98%) rename {internal/lang => lang}/functions_descriptions_test.go (91%) rename {internal/lang => lang}/functions_test.go (99%) rename {internal/lang => lang}/globalref/analyzer.go (94%) rename {internal/lang => lang}/globalref/analyzer_contributing_resources.go (98%) rename {internal/lang => lang}/globalref/analyzer_contributing_resources_test.go (99%) rename {internal/lang => lang}/globalref/analyzer_meta_references.go (99%) rename {internal/lang => lang}/globalref/analyzer_meta_references_shortcuts.go (96%) rename {internal/lang => lang}/globalref/analyzer_meta_references_test.go (98%) rename {internal/lang => lang}/globalref/analyzer_test.go (88%) rename {internal/lang => lang}/globalref/doc.go (100%) rename {internal/lang => lang}/globalref/reference.go (98%) rename {internal/lang => lang}/globalref/testdata/assorted/assorted-root.tf (100%) rename {internal/lang => lang}/globalref/testdata/assorted/child/assorted-child.tf (100%) rename {internal/lang => lang}/globalref/testdata/contributing-resources/compute/contributing-resources-compute.tf (100%) rename {internal/lang => lang}/globalref/testdata/contributing-resources/contributing-resources-root.tf (100%) rename {internal/lang => lang}/globalref/testdata/contributing-resources/network/contributing-resources-network.tf (100%) rename {internal/lang => lang}/marks/marks.go (100%) rename {internal/lang => lang}/references.go (92%) rename {internal/lang => lang}/scope.go (94%) rename {internal/lang => lang}/testdata/functions-test/hello.tmpl (100%) rename {internal/lang => lang}/testdata/functions-test/hello.txt (100%) rename {internal/lang => lang}/testdata/functions-test/subdirectory/hello.tmpl (100%) rename {internal/lang => lang}/testdata/functions-test/subdirectory/hello.txt (100%) rename {internal/lang => lang}/types/type_type.go (100%) rename {internal/lang => lang}/types/types.go (100%) rename {internal/legacy => legacy}/helper/acctest/acctest.go (100%) rename {internal/legacy => legacy}/helper/acctest/random.go (100%) rename {internal/legacy => legacy}/helper/acctest/random_test.go (100%) rename {internal/legacy => legacy}/helper/acctest/remotetests.go (100%) rename {internal/legacy => legacy}/helper/hashcode/hashcode.go (100%) rename {internal/legacy => legacy}/helper/hashcode/hashcode_test.go (100%) rename {internal/legacy => legacy}/helper/schema/backend.go (95%) rename {internal/legacy => legacy}/helper/schema/backend_test.go (100%) rename {internal/legacy => legacy}/helper/schema/core_schema.go (99%) rename {internal/legacy => legacy}/helper/schema/core_schema_test.go (99%) rename {internal/legacy => legacy}/helper/schema/data_source_resource_shim.go (100%) rename {internal/legacy => legacy}/helper/schema/doc.go (100%) rename {internal/legacy => legacy}/helper/schema/equal.go (100%) rename {internal/legacy => legacy}/helper/schema/field_reader.go (100%) rename {internal/legacy => legacy}/helper/schema/field_reader_config.go (99%) rename {internal/legacy => legacy}/helper/schema/field_reader_config_test.go (98%) rename {internal/legacy => legacy}/helper/schema/field_reader_diff.go (99%) rename {internal/legacy => legacy}/helper/schema/field_reader_diff_test.go (99%) rename {internal/legacy => legacy}/helper/schema/field_reader_map.go (100%) rename {internal/legacy => legacy}/helper/schema/field_reader_map_test.go (100%) rename {internal/legacy => legacy}/helper/schema/field_reader_multi.go (100%) rename {internal/legacy => legacy}/helper/schema/field_reader_multi_test.go (98%) rename {internal/legacy => legacy}/helper/schema/field_reader_test.go (100%) rename {internal/legacy => legacy}/helper/schema/field_writer.go (100%) rename {internal/legacy => legacy}/helper/schema/field_writer_map.go (100%) rename {internal/legacy => legacy}/helper/schema/field_writer_map_test.go (100%) rename {internal/legacy => legacy}/helper/schema/getsource_string.go (100%) rename {internal/legacy => legacy}/helper/schema/provider.go (99%) rename {internal/legacy => legacy}/helper/schema/provider_test.go (98%) rename {internal/legacy => legacy}/helper/schema/provisioner.go (97%) rename {internal/legacy => legacy}/helper/schema/provisioner_test.go (99%) rename {internal/legacy => legacy}/helper/schema/resource.go (99%) rename {internal/legacy => legacy}/helper/schema/resource_data.go (99%) rename {internal/legacy => legacy}/helper/schema/resource_data_get_source.go (100%) rename {internal/legacy => legacy}/helper/schema/resource_data_test.go (99%) rename {internal/legacy => legacy}/helper/schema/resource_diff.go (99%) rename {internal/legacy => legacy}/helper/schema/resource_diff_test.go (99%) rename {internal/legacy => legacy}/helper/schema/resource_importer.go (100%) rename {internal/legacy => legacy}/helper/schema/resource_test.go (99%) rename {internal/legacy => legacy}/helper/schema/resource_timeout.go (98%) rename {internal/legacy => legacy}/helper/schema/resource_timeout_test.go (99%) rename {internal/legacy => legacy}/helper/schema/schema.go (99%) rename {internal/legacy => legacy}/helper/schema/schema_test.go (99%) rename {internal/legacy => legacy}/helper/schema/serialize.go (100%) rename {internal/legacy => legacy}/helper/schema/serialize_test.go (100%) rename {internal/legacy => legacy}/helper/schema/set.go (98%) rename {internal/legacy => legacy}/helper/schema/set_test.go (100%) rename {internal/legacy => legacy}/helper/schema/shims.go (95%) rename {internal/legacy => legacy}/helper/schema/shims_test.go (99%) rename {internal/legacy => legacy}/helper/schema/testing.go (89%) rename {internal/legacy => legacy}/helper/schema/valuetype.go (100%) rename {internal/legacy => legacy}/helper/schema/valuetype_string.go (100%) rename {internal/legacy => legacy}/terraform/context_components.go (91%) rename {internal/legacy => legacy}/terraform/diff.go (99%) rename {internal/legacy => legacy}/terraform/diff_test.go (99%) rename {internal/legacy => legacy}/terraform/features.go (100%) rename {internal/legacy => legacy}/terraform/instancetype.go (100%) rename {internal/legacy => legacy}/terraform/instancetype_string.go (100%) rename {internal/legacy => legacy}/terraform/provider_mock.go (98%) rename {internal/legacy => legacy}/terraform/provisioner_mock.go (98%) rename {internal/legacy => legacy}/terraform/resource.go (98%) rename {internal/legacy => legacy}/terraform/resource_address.go (99%) rename {internal/legacy => legacy}/terraform/resource_address_test.go (99%) rename {internal/legacy => legacy}/terraform/resource_mode.go (100%) rename {internal/legacy => legacy}/terraform/resource_mode_string.go (100%) rename {internal/legacy => legacy}/terraform/resource_provider.go (100%) rename {internal/legacy => legacy}/terraform/resource_provider_mock.go (100%) rename {internal/legacy => legacy}/terraform/resource_provisioner.go (96%) rename {internal/legacy => legacy}/terraform/resource_provisioner_mock.go (96%) rename {internal/legacy => legacy}/terraform/resource_test.go (99%) rename {internal/legacy => legacy}/terraform/schemas.go (96%) rename {internal/legacy => legacy}/terraform/state.go (99%) rename {internal/legacy => legacy}/terraform/state_filter.go (100%) rename {internal/legacy => legacy}/terraform/state_test.go (99%) rename {internal/legacy => legacy}/terraform/state_upgrade_v1_to_v2.go (100%) rename {internal/legacy => legacy}/terraform/state_upgrade_v2_to_v3.go (100%) rename {internal/legacy => legacy}/terraform/state_v1.go (100%) rename {internal/legacy => legacy}/terraform/testing.go (100%) rename {internal/legacy => legacy}/terraform/ui_input.go (100%) rename {internal/legacy => legacy}/terraform/ui_input_mock.go (100%) rename {internal/legacy => legacy}/terraform/ui_input_prefix.go (100%) rename {internal/legacy => legacy}/terraform/ui_input_prefix_test.go (100%) rename {internal/legacy => legacy}/terraform/ui_output.go (100%) rename {internal/legacy => legacy}/terraform/ui_output_callback.go (100%) rename {internal/legacy => legacy}/terraform/ui_output_callback_test.go (100%) rename {internal/legacy => legacy}/terraform/ui_output_mock.go (100%) rename {internal/legacy => legacy}/terraform/ui_output_mock_test.go (100%) rename {internal/legacy => legacy}/terraform/upgrade_state_v1_test.go (100%) rename {internal/legacy => legacy}/terraform/upgrade_state_v2_test.go (100%) rename {internal/legacy => legacy}/terraform/util.go (100%) rename {internal/legacy => legacy}/terraform/util_test.go (100%) rename {internal/legacy => legacy}/terraform/version.go (100%) rename {internal/legacy => legacy}/terraform/version_required.go (95%) rename {internal/logging => logging}/indent.go (100%) rename {internal/logging => logging}/indent_test.go (100%) rename {internal/logging => logging}/logging.go (100%) rename {internal/logging => logging}/panic.go (100%) rename {internal/logging => logging}/panic_test.go (100%) rename {internal/modsdir => modsdir}/doc.go (100%) rename {internal/modsdir => modsdir}/manifest.go (99%) rename {internal/modsdir => modsdir}/paths.go (100%) rename {internal/moduledeps => moduledeps}/dependencies.go (93%) rename {internal/moduledeps => moduledeps}/doc.go (100%) rename {internal/moduledeps => moduledeps}/module.go (99%) rename {internal/moduledeps => moduledeps}/module_test.go (97%) rename {internal/moduletest => moduletest}/assertion.go (97%) rename {internal/moduletest => moduletest}/doc.go (100%) rename {internal/moduletest => moduletest}/provider.go (99%) rename {internal/moduletest => moduletest}/provider_test.go (98%) rename {internal/moduletest => moduletest}/status_string.go (100%) rename {internal/moduletest => moduletest}/suite.go (100%) rename {internal/plans => plans}/action.go (100%) rename {internal/plans => plans}/action_string.go (100%) rename {internal/plans => plans}/changes.go (99%) rename {internal/plans => plans}/changes_src.go (98%) rename {internal/plans => plans}/changes_state.go (90%) rename {internal/plans => plans}/changes_sync.go (98%) rename {internal/plans => plans}/changes_test.go (97%) rename {internal/plans => plans}/doc.go (100%) rename {internal/plans => plans}/dynamic_value.go (100%) rename {internal/plans => plans}/internal/planproto/doc.go (100%) rename {internal/plans => plans}/internal/planproto/planfile.pb.go (100%) rename {internal/plans => plans}/internal/planproto/planfile.proto (100%) rename {internal/plans => plans}/mode.go (100%) rename {internal/plans => plans}/mode_string.go (100%) rename {internal/plans => plans}/objchange/action.go (96%) rename {internal/plans => plans}/objchange/compatible.go (99%) rename {internal/plans => plans}/objchange/compatible_test.go (99%) rename {internal/plans => plans}/objchange/doc.go (100%) rename {internal/plans => plans}/objchange/lcs.go (100%) rename {internal/plans => plans}/objchange/lcs_test.go (98%) rename {internal/plans => plans}/objchange/normalize_obj.go (98%) rename {internal/plans => plans}/objchange/normalize_obj_test.go (99%) rename {internal/plans => plans}/objchange/objchange.go (99%) rename {internal/plans => plans}/objchange/objchange_test.go (99%) rename {internal/plans => plans}/objchange/plan_valid.go (99%) rename {internal/plans => plans}/objchange/plan_valid_test.go (99%) rename {internal/plans => plans}/plan.go (97%) rename {internal/plans => plans}/plan_test.go (97%) rename {internal/plans => plans}/planfile/config_snapshot.go (99%) rename {internal/plans => plans}/planfile/config_snapshot_test.go (94%) rename {internal/plans => plans}/planfile/doc.go (100%) rename {internal/plans => plans}/planfile/planfile_test.go (92%) rename {internal/plans => plans}/planfile/reader.go (96%) rename {internal/plans => plans}/planfile/testdata/test-config/.terraform/modules/child_a/child_a.tf (100%) rename {internal/plans => plans}/planfile/testdata/test-config/.terraform/modules/child_a/child_c/child_c.tf (100%) rename {internal/plans => plans}/planfile/testdata/test-config/.terraform/modules/child_b.child_d/child_d.tf (100%) rename {internal/plans => plans}/planfile/testdata/test-config/.terraform/modules/child_b/child_b.tf (100%) rename {internal/plans => plans}/planfile/testdata/test-config/.terraform/modules/modules.json (100%) rename {internal/plans => plans}/planfile/testdata/test-config/root.tf (100%) rename {internal/plans => plans}/planfile/tfplan.go (98%) rename {internal/plans => plans}/planfile/tfplan_test.go (96%) rename {internal/plans => plans}/planfile/writer.go (94%) rename {internal/plans => plans}/resourceinstancechangeactionreason_string.go (100%) rename {internal/plugin => plugin}/convert/diagnostics.go (97%) rename {internal/plugin => plugin}/convert/diagnostics_test.go (98%) rename {internal/plugin => plugin}/convert/schema.go (96%) rename {internal/plugin => plugin}/convert/schema_test.go (98%) rename {internal/plugin => plugin}/discovery/find.go (100%) rename {internal/plugin => plugin}/discovery/find_test.go (100%) rename {internal/plugin => plugin}/discovery/get_cache.go (100%) rename {internal/plugin => plugin}/discovery/get_cache_test.go (100%) rename {internal/plugin => plugin}/discovery/meta.go (100%) rename {internal/plugin => plugin}/discovery/meta_set.go (100%) rename {internal/plugin => plugin}/discovery/meta_set_test.go (100%) rename {internal/plugin => plugin}/discovery/meta_test.go (100%) rename {internal/plugin => plugin}/discovery/requirements.go (100%) rename {internal/plugin => plugin}/discovery/requirements_test.go (100%) rename {internal/plugin => plugin}/discovery/testdata/current-style-plugins/mockos_mockarch/terraform-foo-bar_v0.0.1 (100%) rename {internal/plugin => plugin}/discovery/testdata/current-style-plugins/mockos_mockarch/terraform-foo-missing-version (100%) rename {internal/plugin => plugin}/discovery/testdata/current-style-plugins/mockos_mockarch/terraform-notfoo-bar_v0.0.1 (100%) rename {internal/plugin => plugin}/discovery/testdata/legacy-style-plugins/terraform-foo-bar (100%) rename {internal/plugin => plugin}/discovery/testdata/legacy-style-plugins/terraform-foo-baz (100%) rename {internal/plugin => plugin}/discovery/testdata/legacy-style-plugins/terraform-notfoo-bar (100%) rename {internal/plugin => plugin}/discovery/testdata/not-a-dir (100%) rename {internal/plugin => plugin}/discovery/testdata/plugin-cache/terraform-provider-foo_v0.0.1_x4 (100%) rename {internal/plugin => plugin}/discovery/version.go (100%) rename {internal/plugin => plugin}/discovery/version_set.go (100%) rename {internal/plugin => plugin}/discovery/version_set_test.go (100%) rename {internal/plugin => plugin}/discovery/version_test.go (100%) rename {internal/plugin => plugin}/grpc_error.go (97%) rename {internal/plugin => plugin}/grpc_provider.go (98%) rename {internal/plugin => plugin}/grpc_provider_test.go (98%) rename {internal/plugin => plugin}/grpc_provisioner.go (95%) rename {internal/plugin => plugin}/grpc_provisioner_test.go (92%) create mode 100644 plugin/mock_proto/generate.go rename {internal/plugin => plugin}/mock_proto/mock.go (99%) rename {internal/plugin => plugin}/plugin.go (89%) rename {internal/plugin => plugin}/serve.go (97%) rename {internal/plugin => plugin}/ui_input.go (95%) rename {internal/plugin => plugin}/ui_input_test.go (94%) rename {internal/plugin => plugin}/ui_output.go (90%) rename {internal/plugin => plugin}/ui_output_test.go (92%) rename {internal/plugin6 => plugin6}/convert/diagnostics.go (97%) rename {internal/plugin6 => plugin6}/convert/diagnostics_test.go (98%) rename {internal/plugin6 => plugin6}/convert/schema.go (97%) rename {internal/plugin6 => plugin6}/convert/schema_test.go (99%) rename {internal/plugin6 => plugin6}/doc.go (100%) rename {internal/plugin6 => plugin6}/grpc_error.go (97%) rename {internal/plugin6 => plugin6}/grpc_provider.go (98%) rename {internal/plugin6 => plugin6}/grpc_provider_test.go (98%) rename {internal/plugin6 => plugin6}/mock_proto/generate.go (54%) rename {internal/plugin6 => plugin6}/mock_proto/mock.go (98%) rename {internal/plugin6 => plugin6}/serve.go (97%) create mode 100644 provider-simple-v6/main/main.go rename {internal/provider-simple-v6 => provider-simple-v6}/provider.go (97%) create mode 100644 provider-simple/main/main.go rename {internal/provider-simple => provider-simple}/provider.go (96%) rename {internal/provider-terraform => provider-terraform}/main/main.go (54%) rename {internal/providercache => providercache}/cached_provider.go (98%) rename {internal/providercache => providercache}/cached_provider_test.go (97%) rename {internal/providercache => providercache}/dir.go (98%) rename {internal/providercache => providercache}/dir_modify.go (98%) rename {internal/providercache => providercache}/dir_modify_test.go (97%) rename {internal/providercache => providercache}/dir_test.go (98%) rename {internal/providercache => providercache}/doc.go (100%) rename {internal/providercache => providercache}/installer.go (99%) rename {internal/providercache => providercache}/installer_events.go (98%) rename {internal/providercache => providercache}/installer_events_test.go (98%) rename {internal/providercache => providercache}/installer_test.go (99%) rename {internal/providercache => providercache}/package_install.go (98%) rename {internal/providercache => providercache}/testdata/beep-provider-other-platform/terraform-provider-beep (100%) rename {internal/providercache => providercache}/testdata/beep-provider/terraform-provider-beep (100%) rename {internal/providercache => providercache}/testdata/cachedir/registry.terraform.io/-/legacy/1.0.0/linux_amd64/terraform-provider-legacy (100%) rename {internal/providercache => providercache}/testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/darwin_amd64/terraform-provider-null (100%) rename {internal/providercache => providercache}/testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/linux_amd64/terraform-provider-null (100%) rename {internal/providercache => providercache}/testdata/cachedir/registry.terraform.io/hashicorp/null/invalid (100%) rename {internal/providercache => providercache}/testdata/cachedir/registry.terraform.io/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip (100%) rename {internal/providercache => providercache}/testdata/cachedir/registry.terraform.io/hashicorp/null/terraform-provider-null_invalid.zip (100%) rename {internal/providercache => providercache}/testdata/cachedir/registry.terraform.io/hashicorp/null/terraform-provider-null_invalid_invalid_invalid.zip (100%) rename {internal/providercache => providercache}/testdata/cachedir/registry.terraform.io/hashicorp/random-beta/1.2.0/linux_amd64/terraform-provider-random-beta (100%) rename {internal/providercache => providercache}/testdata/cachedir/registry.terraform.io/hashicorp/random/1.2.0/linux_amd64/terraform-provider-random (100%) rename {internal/providercache => providercache}/testdata/cachedir/registry.terraform.io/missing/executable/2.0.0/linux_amd64/executable (100%) rename {internal/providercache => providercache}/testdata/cachedir/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64/extra-data.txt (100%) rename {internal/providercache => providercache}/testdata/cachedir/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64/terraform-provider-happycloud (100%) rename {internal/providercache => providercache}/testdata/terraform-provider-null_2.1.0_linux_amd64.zip (100%) rename {internal/providers => providers}/addressed_types.go (93%) rename {internal/providers => providers}/addressed_types_test.go (95%) rename {internal/providers => providers}/doc.go (100%) rename {internal/providers => providers}/factory.go (100%) rename {internal/providers => providers}/provider.go (99%) rename {internal/providers => providers}/schemas.go (95%) rename {internal/provisioner-local-exec => provisioner-local-exec}/main/main.go (52%) rename {internal/provisioners => provisioners}/doc.go (100%) rename {internal/provisioners => provisioners}/factory.go (100%) rename {internal/provisioners => provisioners}/provisioner.go (95%) rename {internal/refactoring => refactoring}/move_execute.go (98%) rename {internal/refactoring => refactoring}/move_execute_test.go (99%) rename {internal/refactoring => refactoring}/move_statement.go (97%) rename {internal/refactoring => refactoring}/move_statement_test.go (97%) rename {internal/refactoring => refactoring}/move_validate.go (97%) rename {internal/refactoring => refactoring}/move_validate_test.go (98%) rename {internal/refactoring => refactoring}/testdata/move-statement-implied/child/move-statement-implied.tf (100%) rename {internal/refactoring => refactoring}/testdata/move-statement-implied/move-statement-implied.tf (100%) rename {internal/refactoring => refactoring}/testdata/move-validate-zoo/child/move-validate-child.tf (100%) rename {internal/refactoring => refactoring}/testdata/move-validate-zoo/move-validate-root.tf (100%) rename {internal/registry => registry}/client.go (97%) rename {internal/registry => registry}/client_test.go (98%) rename {internal/registry => registry}/errors.go (95%) rename {internal/registry => registry}/regsrc/friendly_host.go (100%) rename {internal/registry => registry}/regsrc/friendly_host_test.go (100%) rename {internal/registry => registry}/regsrc/module.go (99%) rename {internal/registry => registry}/regsrc/module_test.go (100%) rename {internal/registry => registry}/regsrc/regsrc.go (100%) rename {internal/registry => registry}/response/module.go (100%) rename {internal/registry => registry}/response/module_list.go (100%) rename {internal/registry => registry}/response/module_provider.go (100%) rename {internal/registry => registry}/response/module_versions.go (100%) rename {internal/registry => registry}/response/pagination.go (100%) rename {internal/registry => registry}/response/pagination_test.go (100%) rename {internal/registry => registry}/response/redirect.go (100%) rename {internal/registry => registry}/test/mock_registry.go (97%) rename {internal/repl => repl}/format.go (98%) rename {internal/repl => repl}/format_test.go (98%) rename {internal/repl => repl}/repl.go (100%) rename {internal/repl => repl}/session.go (96%) rename {internal/repl => repl}/session_test.go (96%) rename {internal/repl => repl}/testdata/config-fixture/child/empty.tf (100%) rename {internal/repl => repl}/testdata/config-fixture/repl_test.tf (100%) rename {internal/replacefile => replacefile}/doc.go (100%) rename {internal/replacefile => replacefile}/replacefile_unix.go (100%) rename {internal/replacefile => replacefile}/replacefile_windows.go (100%) rename {internal/replacefile => replacefile}/writefile.go (100%) rename {internal/states => states}/checks.go (98%) rename {internal/states => states}/doc.go (100%) rename {internal/states => states}/instance_generation.go (100%) rename {internal/states => states}/instance_object.go (99%) rename {internal/states => states}/instance_object_src.go (97%) rename {internal/states => states}/instance_object_test.go (97%) rename {internal/states => states}/module.go (99%) rename {internal/states => states}/objectstatus_string.go (100%) rename {internal/states => states}/output_value.go (88%) rename {internal/states => states}/remote/remote.go (94%) rename {internal/states => states}/remote/remote_test.go (100%) rename {internal/states => states}/remote/state.go (97%) rename {internal/states => states}/remote/state_test.go (99%) rename {internal/states => states}/remote/testing.go (94%) rename {internal/states => states}/resource.go (99%) rename {internal/states => states}/resource_test.go (100%) rename {internal/states => states}/state.go (99%) rename {internal/states => states}/state_deepcopy.go (99%) rename {internal/states => states}/state_equal.go (97%) rename {internal/states => states}/state_string.go (98%) rename {internal/states => states}/state_test.go (99%) rename {internal/states => states}/statefile/diagnostics.go (97%) rename {internal/states => states}/statefile/doc.go (100%) rename {internal/states => states}/statefile/file.go (97%) rename {internal/states => states}/statefile/marshal_equal.go (95%) rename {internal/states => states}/statefile/read.go (99%) rename {internal/states => states}/statefile/roundtrip_test.go (100%) rename {internal/states => states}/statefile/testdata/roundtrip/v1-simple.in.tfstate (100%) rename {internal/states => states}/statefile/testdata/roundtrip/v1-simple.out.tfstate (100%) rename {internal/states => states}/statefile/testdata/roundtrip/v3-bigint.in.tfstate (100%) rename {internal/states => states}/statefile/testdata/roundtrip/v3-bigint.out.tfstate (100%) rename {internal/states => states}/statefile/testdata/roundtrip/v3-builtin.in.tfstate (100%) rename {internal/states => states}/statefile/testdata/roundtrip/v3-builtin.out.tfstate (100%) rename {internal/states => states}/statefile/testdata/roundtrip/v3-grabbag.in.tfstate (100%) rename {internal/states => states}/statefile/testdata/roundtrip/v3-grabbag.out.tfstate (100%) rename {internal/states => states}/statefile/testdata/roundtrip/v3-invalid-depends.in.tfstate (100%) rename {internal/states => states}/statefile/testdata/roundtrip/v3-invalid-depends.out.tfstate (100%) rename {internal/states => states}/statefile/testdata/roundtrip/v3-simple.in.tfstate (100%) rename {internal/states => states}/statefile/testdata/roundtrip/v3-simple.out.tfstate (100%) rename {internal/states => states}/statefile/testdata/roundtrip/v4-cbd.in.tfstate (100%) rename {internal/states => states}/statefile/testdata/roundtrip/v4-cbd.out.tfstate (100%) rename {internal/states => states}/statefile/testdata/roundtrip/v4-foreach.in.tfstate (100%) rename {internal/states => states}/statefile/testdata/roundtrip/v4-foreach.out.tfstate (100%) rename {internal/states => states}/statefile/testdata/roundtrip/v4-future.in.tfstate (100%) rename {internal/states => states}/statefile/testdata/roundtrip/v4-future.out.tfstate (100%) rename {internal/states => states}/statefile/testdata/roundtrip/v4-legacy-foreach.in.tfstate (100%) rename {internal/states => states}/statefile/testdata/roundtrip/v4-legacy-foreach.out.tfstate (100%) rename {internal/states => states}/statefile/testdata/roundtrip/v4-legacy-modules.in.tfstate (100%) rename {internal/states => states}/statefile/testdata/roundtrip/v4-legacy-modules.out.tfstate (100%) rename {internal/states => states}/statefile/testdata/roundtrip/v4-legacy-simple.in.tfstate (100%) rename {internal/states => states}/statefile/testdata/roundtrip/v4-legacy-simple.out.tfstate (100%) rename {internal/states => states}/statefile/testdata/roundtrip/v4-modules.in.tfstate (100%) rename {internal/states => states}/statefile/testdata/roundtrip/v4-modules.out.tfstate (100%) rename {internal/states => states}/statefile/testdata/roundtrip/v4-simple.in.tfstate (100%) rename {internal/states => states}/statefile/testdata/roundtrip/v4-simple.out.tfstate (100%) rename {internal/states => states}/statefile/version0.go (100%) rename {internal/states => states}/statefile/version1.go (99%) rename {internal/states => states}/statefile/version1_upgrade.go (100%) rename {internal/states => states}/statefile/version2.go (99%) rename {internal/states => states}/statefile/version2_upgrade.go (100%) rename {internal/states => states}/statefile/version3.go (96%) rename {internal/states => states}/statefile/version3_upgrade.go (98%) rename {internal/states => states}/statefile/version4.go (99%) rename {internal/states => states}/statefile/version4_test.go (99%) rename {internal/states => states}/statefile/write.go (100%) rename {internal/states => states}/statemgr/doc.go (100%) rename {internal/states => states}/statemgr/filesystem.go (98%) rename {internal/states => states}/statemgr/filesystem_lock_unix.go (100%) rename {internal/states => states}/statemgr/filesystem_lock_windows.go (100%) rename {internal/states => states}/statemgr/filesystem_test.go (98%) rename {internal/states => states}/statemgr/helper.go (91%) rename {internal/states => states}/statemgr/lineage.go (100%) rename {internal/states => states}/statemgr/lock.go (90%) rename {internal/states => states}/statemgr/lock_test.go (100%) rename {internal/states => states}/statemgr/locker.go (100%) rename {internal/states => states}/statemgr/migrate.go (99%) rename {internal/states => states}/statemgr/migrate_test.go (95%) rename {internal/states => states}/statemgr/persistent.go (97%) rename {internal/states => states}/statemgr/plan.go (96%) rename {internal/states => states}/statemgr/snapshotmetarel_string.go (100%) rename {internal/states => states}/statemgr/statemgr.go (100%) rename {internal/states => states}/statemgr/statemgr_fake.go (97%) rename {internal/states => states}/statemgr/statemgr_test.go (97%) rename {internal/states => states}/statemgr/testdata/lockstate.go (88%) rename {internal/states => states}/statemgr/testing.go (96%) rename {internal/states => states}/statemgr/transient.go (98%) rename {internal/states => states}/statemgr/transient_inmem.go (94%) rename {internal/states => states}/sync.go (99%) rename {internal/terminal => terminal}/impl_others.go (100%) rename {internal/terminal => terminal}/impl_windows.go (100%) rename {internal/terminal => terminal}/stream.go (100%) rename {internal/terminal => terminal}/streams.go (100%) rename {internal/terminal => terminal}/streams_test.go (100%) rename {internal/terminal => terminal}/testing.go (100%) rename {internal/tfdiags => tfdiags}/config_traversals.go (100%) rename {internal/tfdiags => tfdiags}/consolidate_warnings.go (100%) rename {internal/tfdiags => tfdiags}/consolidate_warnings_test.go (92%) rename {internal/tfdiags => tfdiags}/contextual.go (100%) rename {internal/tfdiags => tfdiags}/contextual_test.go (100%) rename {internal/tfdiags => tfdiags}/diagnostic.go (100%) rename {internal/tfdiags => tfdiags}/diagnostic_base.go (100%) rename {internal/tfdiags => tfdiags}/diagnostic_extra.go (100%) rename {internal/tfdiags => tfdiags}/diagnostics.go (100%) rename {internal/tfdiags => tfdiags}/diagnostics_test.go (100%) rename {internal/tfdiags => tfdiags}/doc.go (100%) rename {internal/tfdiags => tfdiags}/error.go (100%) rename {internal/tfdiags => tfdiags}/hcl.go (100%) rename {internal/tfdiags => tfdiags}/hcl_test.go (100%) rename {internal/tfdiags => tfdiags}/rpc_friendly.go (69%) rename {internal/tfdiags => tfdiags}/rpc_friendly_test.go (95%) rename {internal/tfdiags => tfdiags}/severity_string.go (100%) rename {internal/tfdiags => tfdiags}/simple_warning.go (100%) rename {internal/tfdiags => tfdiags}/source_range.go (100%) rename {internal/tfdiags => tfdiags}/sourceless.go (100%) rename {internal/tfplugin5 => tfplugin5}/tfplugin5.pb.go (100%) rename {internal/tfplugin5 => tfplugin5}/tfplugin5.proto (100%) rename {internal/tfplugin6 => tfplugin6}/tfplugin6.pb.go (100%) rename {internal/tfplugin6 => tfplugin6}/tfplugin6.proto (100%) diff --git a/internal/addrs/check.go b/addrs/check.go similarity index 99% rename from internal/addrs/check.go rename to addrs/check.go index 430b50c990d8..0e4a8b028e16 100644 --- a/internal/addrs/check.go +++ b/addrs/check.go @@ -5,7 +5,7 @@ import ( "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" ) // Check is the address of a check rule within a checkable object. diff --git a/internal/addrs/checkablekind_string.go b/addrs/checkablekind_string.go similarity index 100% rename from internal/addrs/checkablekind_string.go rename to addrs/checkablekind_string.go diff --git a/internal/addrs/checktype_string.go b/addrs/checktype_string.go similarity index 100% rename from internal/addrs/checktype_string.go rename to addrs/checktype_string.go diff --git a/internal/addrs/count_attr.go b/addrs/count_attr.go similarity index 100% rename from internal/addrs/count_attr.go rename to addrs/count_attr.go diff --git a/internal/addrs/doc.go b/addrs/doc.go similarity index 100% rename from internal/addrs/doc.go rename to addrs/doc.go diff --git a/internal/addrs/for_each_attr.go b/addrs/for_each_attr.go similarity index 100% rename from internal/addrs/for_each_attr.go rename to addrs/for_each_attr.go diff --git a/internal/addrs/input_variable.go b/addrs/input_variable.go similarity index 100% rename from internal/addrs/input_variable.go rename to addrs/input_variable.go diff --git a/internal/addrs/instance_key.go b/addrs/instance_key.go similarity index 100% rename from internal/addrs/instance_key.go rename to addrs/instance_key.go diff --git a/internal/addrs/instance_key_test.go b/addrs/instance_key_test.go similarity index 100% rename from internal/addrs/instance_key_test.go rename to addrs/instance_key_test.go diff --git a/internal/addrs/local_value.go b/addrs/local_value.go similarity index 100% rename from internal/addrs/local_value.go rename to addrs/local_value.go diff --git a/internal/addrs/map.go b/addrs/map.go similarity index 100% rename from internal/addrs/map.go rename to addrs/map.go diff --git a/internal/addrs/map_test.go b/addrs/map_test.go similarity index 100% rename from internal/addrs/map_test.go rename to addrs/map_test.go diff --git a/internal/addrs/module.go b/addrs/module.go similarity index 100% rename from internal/addrs/module.go rename to addrs/module.go diff --git a/internal/addrs/module_call.go b/addrs/module_call.go similarity index 100% rename from internal/addrs/module_call.go rename to addrs/module_call.go diff --git a/internal/addrs/module_instance.go b/addrs/module_instance.go similarity index 99% rename from internal/addrs/module_instance.go rename to addrs/module_instance.go index f197dc144f95..44bea48a20ce 100644 --- a/internal/addrs/module_instance.go +++ b/addrs/module_instance.go @@ -9,7 +9,7 @@ import ( "github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty/gocty" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" ) // ModuleInstance is an address for a particular module instance within the diff --git a/internal/addrs/module_instance_test.go b/addrs/module_instance_test.go similarity index 100% rename from internal/addrs/module_instance_test.go rename to addrs/module_instance_test.go diff --git a/internal/addrs/module_package.go b/addrs/module_package.go similarity index 100% rename from internal/addrs/module_package.go rename to addrs/module_package.go diff --git a/internal/addrs/module_source.go b/addrs/module_source.go similarity index 99% rename from internal/addrs/module_source.go rename to addrs/module_source.go index 82000dbc4181..cc41f4e4309d 100644 --- a/internal/addrs/module_source.go +++ b/addrs/module_source.go @@ -6,7 +6,7 @@ import ( "strings" tfaddr "github.com/hashicorp/terraform-registry-address" - "github.com/hashicorp/terraform/internal/getmodules" + "github.com/hashicorp/terraform/getmodules" ) // ModuleSource is the general type for all three of the possible module source diff --git a/internal/addrs/module_source_test.go b/addrs/module_source_test.go similarity index 100% rename from internal/addrs/module_source_test.go rename to addrs/module_source_test.go diff --git a/internal/addrs/module_test.go b/addrs/module_test.go similarity index 100% rename from internal/addrs/module_test.go rename to addrs/module_test.go diff --git a/internal/addrs/move_endpoint.go b/addrs/move_endpoint.go similarity index 99% rename from internal/addrs/move_endpoint.go rename to addrs/move_endpoint.go index 765b66f5eecc..e83325365842 100644 --- a/internal/addrs/move_endpoint.go +++ b/addrs/move_endpoint.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" ) // MoveEndpoint is to AbsMoveable and ConfigMoveable what Target is to diff --git a/internal/addrs/move_endpoint_kind.go b/addrs/move_endpoint_kind.go similarity index 100% rename from internal/addrs/move_endpoint_kind.go rename to addrs/move_endpoint_kind.go diff --git a/internal/addrs/move_endpoint_module.go b/addrs/move_endpoint_module.go similarity index 99% rename from internal/addrs/move_endpoint_module.go rename to addrs/move_endpoint_module.go index f2c1408d66b1..a230a60d6525 100644 --- a/internal/addrs/move_endpoint_module.go +++ b/addrs/move_endpoint_module.go @@ -7,7 +7,7 @@ import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" ) // anyKeyImpl is the InstanceKey representation indicating a wildcard, which diff --git a/internal/addrs/move_endpoint_module_test.go b/addrs/move_endpoint_module_test.go similarity index 99% rename from internal/addrs/move_endpoint_module_test.go rename to addrs/move_endpoint_module_test.go index c1643d44c257..d07fa7ba0c23 100644 --- a/internal/addrs/move_endpoint_module_test.go +++ b/addrs/move_endpoint_module_test.go @@ -7,7 +7,7 @@ import ( "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" ) func TestModuleInstanceMoveDestination(t *testing.T) { diff --git a/internal/addrs/move_endpoint_test.go b/addrs/move_endpoint_test.go similarity index 100% rename from internal/addrs/move_endpoint_test.go rename to addrs/move_endpoint_test.go diff --git a/internal/addrs/moveable.go b/addrs/moveable.go similarity index 100% rename from internal/addrs/moveable.go rename to addrs/moveable.go diff --git a/internal/addrs/moveendpointkind_string.go b/addrs/moveendpointkind_string.go similarity index 100% rename from internal/addrs/moveendpointkind_string.go rename to addrs/moveendpointkind_string.go diff --git a/internal/addrs/output_value.go b/addrs/output_value.go similarity index 99% rename from internal/addrs/output_value.go rename to addrs/output_value.go index ff76556b2ac9..343e0299d76e 100644 --- a/internal/addrs/output_value.go +++ b/addrs/output_value.go @@ -5,7 +5,7 @@ import ( "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" ) // OutputValue is the address of an output value, in the context of the module diff --git a/internal/addrs/output_value_test.go b/addrs/output_value_test.go similarity index 100% rename from internal/addrs/output_value_test.go rename to addrs/output_value_test.go diff --git a/internal/addrs/parse_ref.go b/addrs/parse_ref.go similarity index 99% rename from internal/addrs/parse_ref.go rename to addrs/parse_ref.go index bd5bcc7c51ae..f9413cbd4094 100644 --- a/internal/addrs/parse_ref.go +++ b/addrs/parse_ref.go @@ -6,7 +6,7 @@ import ( "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/addrs/parse_ref_test.go b/addrs/parse_ref_test.go similarity index 99% rename from internal/addrs/parse_ref_test.go rename to addrs/parse_ref_test.go index 52c9b2cd33e2..dceb1144e155 100644 --- a/internal/addrs/parse_ref_test.go +++ b/addrs/parse_ref_test.go @@ -6,7 +6,7 @@ import ( "github.com/go-test/deep" "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/addrs/parse_target.go b/addrs/parse_target.go similarity index 99% rename from internal/addrs/parse_target.go rename to addrs/parse_target.go index 378e4de6a5fb..2a4d0ecbb1e6 100644 --- a/internal/addrs/parse_target.go +++ b/addrs/parse_target.go @@ -6,7 +6,7 @@ import ( "github.com/hashicorp/hcl/v2/hclsyntax" "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" ) // Target describes a targeted address with source location information. diff --git a/internal/addrs/parse_target_test.go b/addrs/parse_target_test.go similarity index 99% rename from internal/addrs/parse_target_test.go rename to addrs/parse_target_test.go index 6e838d0e51ad..84796084f0fc 100644 --- a/internal/addrs/parse_target_test.go +++ b/addrs/parse_target_test.go @@ -6,7 +6,7 @@ import ( "github.com/go-test/deep" "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" ) func TestParseTarget(t *testing.T) { diff --git a/internal/addrs/path_attr.go b/addrs/path_attr.go similarity index 100% rename from internal/addrs/path_attr.go rename to addrs/path_attr.go diff --git a/internal/addrs/provider.go b/addrs/provider.go similarity index 99% rename from internal/addrs/provider.go rename to addrs/provider.go index 7130de1ea108..ce41d650ffd7 100644 --- a/internal/addrs/provider.go +++ b/addrs/provider.go @@ -4,7 +4,7 @@ import ( "github.com/hashicorp/hcl/v2" tfaddr "github.com/hashicorp/terraform-registry-address" svchost "github.com/hashicorp/terraform-svchost" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" ) // Provider encapsulates a single provider type. In the future this will be diff --git a/internal/addrs/provider_config.go b/addrs/provider_config.go similarity index 99% rename from internal/addrs/provider_config.go rename to addrs/provider_config.go index 3790c46d6b44..4300deba10f1 100644 --- a/internal/addrs/provider_config.go +++ b/addrs/provider_config.go @@ -4,7 +4,7 @@ import ( "fmt" "strings" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" "github.com/zclconf/go-cty/cty" "github.com/hashicorp/hcl/v2" diff --git a/internal/addrs/provider_config_test.go b/addrs/provider_config_test.go similarity index 100% rename from internal/addrs/provider_config_test.go rename to addrs/provider_config_test.go diff --git a/internal/addrs/provider_test.go b/addrs/provider_test.go similarity index 100% rename from internal/addrs/provider_test.go rename to addrs/provider_test.go diff --git a/internal/addrs/referenceable.go b/addrs/referenceable.go similarity index 100% rename from internal/addrs/referenceable.go rename to addrs/referenceable.go diff --git a/internal/addrs/resource.go b/addrs/resource.go similarity index 100% rename from internal/addrs/resource.go rename to addrs/resource.go diff --git a/internal/addrs/resource_phase.go b/addrs/resource_phase.go similarity index 100% rename from internal/addrs/resource_phase.go rename to addrs/resource_phase.go diff --git a/internal/addrs/resource_test.go b/addrs/resource_test.go similarity index 100% rename from internal/addrs/resource_test.go rename to addrs/resource_test.go diff --git a/internal/addrs/resourcemode_string.go b/addrs/resourcemode_string.go similarity index 100% rename from internal/addrs/resourcemode_string.go rename to addrs/resourcemode_string.go diff --git a/internal/addrs/self.go b/addrs/self.go similarity index 100% rename from internal/addrs/self.go rename to addrs/self.go diff --git a/internal/addrs/set.go b/addrs/set.go similarity index 100% rename from internal/addrs/set.go rename to addrs/set.go diff --git a/internal/addrs/target_test.go b/addrs/target_test.go similarity index 100% rename from internal/addrs/target_test.go rename to addrs/target_test.go diff --git a/internal/addrs/targetable.go b/addrs/targetable.go similarity index 100% rename from internal/addrs/targetable.go rename to addrs/targetable.go diff --git a/internal/addrs/terraform_attr.go b/addrs/terraform_attr.go similarity index 100% rename from internal/addrs/terraform_attr.go rename to addrs/terraform_attr.go diff --git a/internal/addrs/unique_key.go b/addrs/unique_key.go similarity index 100% rename from internal/addrs/unique_key.go rename to addrs/unique_key.go diff --git a/internal/addrs/unique_key_test.go b/addrs/unique_key_test.go similarity index 100% rename from internal/addrs/unique_key_test.go rename to addrs/unique_key_test.go diff --git a/internal/backend/backend.go b/backend/backend.go similarity index 95% rename from internal/backend/backend.go rename to backend/backend.go index 58e4398a698b..03100c0eb93e 100644 --- a/internal/backend/backend.go +++ b/backend/backend.go @@ -11,19 +11,19 @@ import ( "log" "os" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/command/clistate" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configload" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/depsfile" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/plans/planfile" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/command/clistate" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/depsfile" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/plans/planfile" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" "github.com/mitchellh/go-homedir" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/backend/backend_test.go b/backend/backend_test.go similarity index 100% rename from internal/backend/backend_test.go rename to backend/backend_test.go diff --git a/internal/backend/cli.go b/backend/cli.go similarity index 97% rename from internal/backend/cli.go rename to backend/cli.go index 0a73b122fa9c..46a357e836c2 100644 --- a/internal/backend/cli.go +++ b/backend/cli.go @@ -4,8 +4,8 @@ import ( "github.com/mitchellh/cli" "github.com/mitchellh/colorstring" - "github.com/hashicorp/terraform/internal/terminal" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/terminal" + "github.com/hashicorp/terraform/terraform" ) // CLI is an optional interface that can be implemented to be initialized diff --git a/internal/backend/init/deprecate_test.go b/backend/init/deprecate_test.go similarity index 89% rename from internal/backend/init/deprecate_test.go rename to backend/init/deprecate_test.go index f84cab808da8..c45d62d2b37b 100644 --- a/internal/backend/init/deprecate_test.go +++ b/backend/init/deprecate_test.go @@ -3,7 +3,7 @@ package init import ( "testing" - "github.com/hashicorp/terraform/internal/backend/remote-state/inmem" + "github.com/hashicorp/terraform/backend/remote-state/inmem" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/backend/init/init.go b/backend/init/init.go similarity index 81% rename from internal/backend/init/init.go rename to backend/init/init.go index b437b3035147..b77f56ae2452 100644 --- a/internal/backend/init/init.go +++ b/backend/init/init.go @@ -6,23 +6,23 @@ import ( "sync" "github.com/hashicorp/terraform-svchost/disco" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/tfdiags" "github.com/zclconf/go-cty/cty" - backendLocal "github.com/hashicorp/terraform/internal/backend/local" - backendRemote "github.com/hashicorp/terraform/internal/backend/remote" - backendAzure "github.com/hashicorp/terraform/internal/backend/remote-state/azure" - backendConsul "github.com/hashicorp/terraform/internal/backend/remote-state/consul" - backendCos "github.com/hashicorp/terraform/internal/backend/remote-state/cos" - backendGCS "github.com/hashicorp/terraform/internal/backend/remote-state/gcs" - backendHTTP "github.com/hashicorp/terraform/internal/backend/remote-state/http" - backendInmem "github.com/hashicorp/terraform/internal/backend/remote-state/inmem" - backendKubernetes "github.com/hashicorp/terraform/internal/backend/remote-state/kubernetes" - backendOSS "github.com/hashicorp/terraform/internal/backend/remote-state/oss" - backendPg "github.com/hashicorp/terraform/internal/backend/remote-state/pg" - backendS3 "github.com/hashicorp/terraform/internal/backend/remote-state/s3" - backendCloud "github.com/hashicorp/terraform/internal/cloud" + backendLocal "github.com/hashicorp/terraform/backend/local" + backendRemote "github.com/hashicorp/terraform/backend/remote" + backendAzure "github.com/hashicorp/terraform/backend/remote-state/azure" + backendConsul "github.com/hashicorp/terraform/backend/remote-state/consul" + backendCos "github.com/hashicorp/terraform/backend/remote-state/cos" + backendGCS "github.com/hashicorp/terraform/backend/remote-state/gcs" + backendHTTP "github.com/hashicorp/terraform/backend/remote-state/http" + backendInmem "github.com/hashicorp/terraform/backend/remote-state/inmem" + backendKubernetes "github.com/hashicorp/terraform/backend/remote-state/kubernetes" + backendOSS "github.com/hashicorp/terraform/backend/remote-state/oss" + backendPg "github.com/hashicorp/terraform/backend/remote-state/pg" + backendS3 "github.com/hashicorp/terraform/backend/remote-state/s3" + backendCloud "github.com/hashicorp/terraform/cloud" ) // backends is the list of available backends. This is a global variable diff --git a/internal/backend/init/init_test.go b/backend/init/init_test.go similarity index 100% rename from internal/backend/init/init_test.go rename to backend/init/init_test.go diff --git a/internal/backend/local/backend.go b/backend/local/backend.go similarity index 97% rename from internal/backend/local/backend.go rename to backend/local/backend.go index de0e62d48194..8520e68a5b38 100644 --- a/internal/backend/local/backend.go +++ b/backend/local/backend.go @@ -11,13 +11,13 @@ import ( "sort" "sync" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/logging" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/logging" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/backend/local/backend_apply.go b/backend/local/backend_apply.go similarity index 95% rename from internal/backend/local/backend_apply.go rename to backend/local/backend_apply.go index 23d72fd97509..2321da53a8b9 100644 --- a/internal/backend/local/backend_apply.go +++ b/backend/local/backend_apply.go @@ -6,15 +6,15 @@ import ( "fmt" "log" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/logging" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/statefile" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/logging" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/statefile" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" ) // test hook called between plan+apply during opApply diff --git a/internal/backend/local/backend_apply_test.go b/backend/local/backend_apply_test.go similarity index 92% rename from internal/backend/local/backend_apply_test.go rename to backend/local/backend_apply_test.go index 493000a802b3..6d54a76b1bb3 100644 --- a/internal/backend/local/backend_apply_test.go +++ b/backend/local/backend_apply_test.go @@ -11,21 +11,21 @@ import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/clistate" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/depsfile" - "github.com/hashicorp/terraform/internal/initwd" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/terminal" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/clistate" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/depsfile" + "github.com/hashicorp/terraform/initwd" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/terminal" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" ) func TestLocal_applyBasic(t *testing.T) { diff --git a/internal/backend/local/backend_local.go b/backend/local/backend_local.go similarity index 97% rename from internal/backend/local/backend_local.go rename to backend/local/backend_local.go index 84646ab48297..0c71b31320ce 100644 --- a/internal/backend/local/backend_local.go +++ b/backend/local/backend_local.go @@ -7,13 +7,13 @@ import ( "sort" "strings" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configload" - "github.com/hashicorp/terraform/internal/plans/planfile" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/plans/planfile" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/backend/local/backend_local_test.go b/backend/local/backend_local_test.go similarity index 88% rename from internal/backend/local/backend_local_test.go rename to backend/local/backend_local_test.go index 827c05da9ea3..ffd540cc30d7 100644 --- a/internal/backend/local/backend_local_test.go +++ b/backend/local/backend_local_test.go @@ -8,21 +8,21 @@ import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/clistate" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/configs/configload" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/initwd" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/plans/planfile" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/statefile" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/terminal" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/clistate" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/initwd" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/plans/planfile" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/statefile" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/terminal" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" ) func TestLocalRun(t *testing.T) { diff --git a/internal/backend/local/backend_plan.go b/backend/local/backend_plan.go similarity index 93% rename from internal/backend/local/backend_plan.go rename to backend/local/backend_plan.go index 52aaad11e04d..48605cfb12c0 100644 --- a/internal/backend/local/backend_plan.go +++ b/backend/local/backend_plan.go @@ -5,14 +5,14 @@ import ( "fmt" "log" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/logging" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/plans/planfile" - "github.com/hashicorp/terraform/internal/states/statefile" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/logging" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/plans/planfile" + "github.com/hashicorp/terraform/states/statefile" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" ) func (b *Local) opPlan( diff --git a/internal/backend/local/backend_plan_test.go b/backend/local/backend_plan_test.go similarity index 97% rename from internal/backend/local/backend_plan_test.go rename to backend/local/backend_plan_test.go index 9dbed9953213..f693c1a310c0 100644 --- a/internal/backend/local/backend_plan_test.go +++ b/backend/local/backend_plan_test.go @@ -7,19 +7,19 @@ import ( "strings" "testing" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/clistate" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/depsfile" - "github.com/hashicorp/terraform/internal/initwd" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/plans/planfile" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/terminal" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/clistate" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/depsfile" + "github.com/hashicorp/terraform/initwd" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/plans/planfile" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/terminal" + "github.com/hashicorp/terraform/terraform" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/backend/local/backend_refresh.go b/backend/local/backend_refresh.go similarity index 91% rename from internal/backend/local/backend_refresh.go rename to backend/local/backend_refresh.go index 244e8e89bb6c..84fa5130feb7 100644 --- a/internal/backend/local/backend_refresh.go +++ b/backend/local/backend_refresh.go @@ -6,11 +6,11 @@ import ( "log" "os" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/logging" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/logging" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/tfdiags" ) func (b *Local) opRefresh( diff --git a/internal/backend/local/backend_refresh_test.go b/backend/local/backend_refresh_test.go similarity index 92% rename from internal/backend/local/backend_refresh_test.go rename to backend/local/backend_refresh_test.go index 886c184181c2..78511df2c21a 100644 --- a/internal/backend/local/backend_refresh_test.go +++ b/backend/local/backend_refresh_test.go @@ -6,18 +6,18 @@ import ( "strings" "testing" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/clistate" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/depsfile" - "github.com/hashicorp/terraform/internal/initwd" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/terminal" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/clistate" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/depsfile" + "github.com/hashicorp/terraform/initwd" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/terminal" + "github.com/hashicorp/terraform/terraform" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/backend/local/backend_test.go b/backend/local/backend_test.go similarity index 96% rename from internal/backend/local/backend_test.go rename to backend/local/backend_test.go index 5484ac79650d..cd548c99cd8d 100644 --- a/internal/backend/local/backend_test.go +++ b/backend/local/backend_test.go @@ -8,9 +8,9 @@ import ( "strings" "testing" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/states/statefile" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/states/statefile" + "github.com/hashicorp/terraform/states/statemgr" ) func TestLocal_impl(t *testing.T) { diff --git a/internal/backend/local/cli.go b/backend/local/cli.go similarity index 94% rename from internal/backend/local/cli.go rename to backend/local/cli.go index 41d2477c6a91..9963cbee6b39 100644 --- a/internal/backend/local/cli.go +++ b/backend/local/cli.go @@ -3,7 +3,7 @@ package local import ( "log" - "github.com/hashicorp/terraform/internal/backend" + "github.com/hashicorp/terraform/backend" ) // backend.CLI impl. diff --git a/internal/backend/local/hook_state.go b/backend/local/hook_state.go similarity index 77% rename from internal/backend/local/hook_state.go rename to backend/local/hook_state.go index 4c11496c2502..c54f22371fa0 100644 --- a/internal/backend/local/hook_state.go +++ b/backend/local/hook_state.go @@ -3,9 +3,9 @@ package local import ( "sync" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/terraform" ) // StateHook is a hook that continuously updates the state by calling diff --git a/internal/backend/local/hook_state_test.go b/backend/local/hook_state_test.go similarity index 82% rename from internal/backend/local/hook_state_test.go rename to backend/local/hook_state_test.go index 6e86ac728f2a..715f7d27a472 100644 --- a/internal/backend/local/hook_state_test.go +++ b/backend/local/hook_state_test.go @@ -3,8 +3,8 @@ package local import ( "testing" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/terraform" ) func TestStateHook_impl(t *testing.T) { diff --git a/internal/backend/local/local_test.go b/backend/local/local_test.go similarity index 68% rename from internal/backend/local/local_test.go rename to backend/local/local_test.go index e447921e0938..edaedf22c046 100644 --- a/internal/backend/local/local_test.go +++ b/backend/local/local_test.go @@ -5,7 +5,7 @@ import ( "os" "testing" - _ "github.com/hashicorp/terraform/internal/logging" + _ "github.com/hashicorp/terraform/logging" ) func TestMain(m *testing.M) { diff --git a/internal/backend/local/testdata/apply-empty/hello.txt b/backend/local/testdata/apply-empty/hello.txt similarity index 100% rename from internal/backend/local/testdata/apply-empty/hello.txt rename to backend/local/testdata/apply-empty/hello.txt diff --git a/internal/backend/local/testdata/apply-error/main.tf b/backend/local/testdata/apply-error/main.tf similarity index 100% rename from internal/backend/local/testdata/apply-error/main.tf rename to backend/local/testdata/apply-error/main.tf diff --git a/internal/backend/local/testdata/apply/main.tf b/backend/local/testdata/apply/main.tf similarity index 100% rename from internal/backend/local/testdata/apply/main.tf rename to backend/local/testdata/apply/main.tf diff --git a/internal/backend/local/testdata/destroy-with-ds/main.tf b/backend/local/testdata/destroy-with-ds/main.tf similarity index 100% rename from internal/backend/local/testdata/destroy-with-ds/main.tf rename to backend/local/testdata/destroy-with-ds/main.tf diff --git a/internal/backend/local/testdata/empty/.gitignore b/backend/local/testdata/empty/.gitignore similarity index 100% rename from internal/backend/local/testdata/empty/.gitignore rename to backend/local/testdata/empty/.gitignore diff --git a/internal/backend/local/testdata/invalid/invalid.tf b/backend/local/testdata/invalid/invalid.tf similarity index 100% rename from internal/backend/local/testdata/invalid/invalid.tf rename to backend/local/testdata/invalid/invalid.tf diff --git a/internal/backend/local/testdata/plan-cbd/main.tf b/backend/local/testdata/plan-cbd/main.tf similarity index 100% rename from internal/backend/local/testdata/plan-cbd/main.tf rename to backend/local/testdata/plan-cbd/main.tf diff --git a/internal/backend/local/testdata/plan-module-outputs-changed/main.tf b/backend/local/testdata/plan-module-outputs-changed/main.tf similarity index 100% rename from internal/backend/local/testdata/plan-module-outputs-changed/main.tf rename to backend/local/testdata/plan-module-outputs-changed/main.tf diff --git a/internal/backend/local/testdata/plan-module-outputs-changed/mod/main.tf b/backend/local/testdata/plan-module-outputs-changed/mod/main.tf similarity index 100% rename from internal/backend/local/testdata/plan-module-outputs-changed/mod/main.tf rename to backend/local/testdata/plan-module-outputs-changed/mod/main.tf diff --git a/internal/backend/local/testdata/plan-outputs-changed/main.tf b/backend/local/testdata/plan-outputs-changed/main.tf similarity index 100% rename from internal/backend/local/testdata/plan-outputs-changed/main.tf rename to backend/local/testdata/plan-outputs-changed/main.tf diff --git a/internal/backend/local/testdata/plan-outputs-changed/submodule/main.tf b/backend/local/testdata/plan-outputs-changed/submodule/main.tf similarity index 100% rename from internal/backend/local/testdata/plan-outputs-changed/submodule/main.tf rename to backend/local/testdata/plan-outputs-changed/submodule/main.tf diff --git a/internal/backend/local/testdata/plan/main.tf b/backend/local/testdata/plan/main.tf similarity index 100% rename from internal/backend/local/testdata/plan/main.tf rename to backend/local/testdata/plan/main.tf diff --git a/internal/backend/local/testdata/refresh-provider-config/main.tf b/backend/local/testdata/refresh-provider-config/main.tf similarity index 100% rename from internal/backend/local/testdata/refresh-provider-config/main.tf rename to backend/local/testdata/refresh-provider-config/main.tf diff --git a/internal/backend/local/testdata/refresh-var-unset/main.tf b/backend/local/testdata/refresh-var-unset/main.tf similarity index 100% rename from internal/backend/local/testdata/refresh-var-unset/main.tf rename to backend/local/testdata/refresh-var-unset/main.tf diff --git a/internal/backend/local/testdata/refresh/main.tf b/backend/local/testdata/refresh/main.tf similarity index 100% rename from internal/backend/local/testdata/refresh/main.tf rename to backend/local/testdata/refresh/main.tf diff --git a/internal/backend/local/testing.go b/backend/local/testing.go similarity index 95% rename from internal/backend/local/testing.go rename to backend/local/testing.go index 2958196b1def..35a805324cab 100644 --- a/internal/backend/local/testing.go +++ b/backend/local/testing.go @@ -6,13 +6,13 @@ import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/terraform" ) // TestLocal returns a configured Local struct with temporary paths and diff --git a/internal/backend/operation_type.go b/backend/operation_type.go similarity index 100% rename from internal/backend/operation_type.go rename to backend/operation_type.go diff --git a/internal/backend/operationtype_string.go b/backend/operationtype_string.go similarity index 100% rename from internal/backend/operationtype_string.go rename to backend/operationtype_string.go diff --git a/internal/backend/remote-state/azure/arm_client.go b/backend/remote-state/azure/arm_client.go similarity index 99% rename from internal/backend/remote-state/azure/arm_client.go rename to backend/remote-state/azure/arm_client.go index d548c30b7ba5..ae111b1dd8db 100644 --- a/internal/backend/remote-state/azure/arm_client.go +++ b/backend/remote-state/azure/arm_client.go @@ -13,7 +13,7 @@ import ( "github.com/Azure/go-autorest/autorest/azure" "github.com/hashicorp/go-azure-helpers/authentication" "github.com/hashicorp/go-azure-helpers/sender" - "github.com/hashicorp/terraform/internal/httpclient" + "github.com/hashicorp/terraform/httpclient" "github.com/hashicorp/terraform/version" "github.com/manicminer/hamilton/environments" "github.com/tombuildsstuff/giovanni/storage/2018-11-09/blob/blobs" diff --git a/internal/backend/remote-state/azure/backend.go b/backend/remote-state/azure/backend.go similarity index 98% rename from internal/backend/remote-state/azure/backend.go rename to backend/remote-state/azure/backend.go index f21b0ba4e255..dacc0b9aad9d 100644 --- a/internal/backend/remote-state/azure/backend.go +++ b/backend/remote-state/azure/backend.go @@ -4,8 +4,8 @@ import ( "context" "fmt" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/legacy/helper/schema" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/legacy/helper/schema" ) // New creates a new backend for Azure remote state. diff --git a/internal/backend/remote-state/azure/backend_state.go b/backend/remote-state/azure/backend_state.go similarity index 94% rename from internal/backend/remote-state/azure/backend_state.go rename to backend/remote-state/azure/backend_state.go index fbbb855d0091..60d59f1b643a 100644 --- a/internal/backend/remote-state/azure/backend_state.go +++ b/backend/remote-state/azure/backend_state.go @@ -6,10 +6,10 @@ import ( "sort" "strings" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/remote" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/remote" + "github.com/hashicorp/terraform/states/statemgr" "github.com/tombuildsstuff/giovanni/storage/2018-11-09/blob/blobs" "github.com/tombuildsstuff/giovanni/storage/2018-11-09/blob/containers" ) diff --git a/internal/backend/remote-state/azure/backend_test.go b/backend/remote-state/azure/backend_test.go similarity index 99% rename from internal/backend/remote-state/azure/backend_test.go rename to backend/remote-state/azure/backend_test.go index fa5b0a9f1666..ea0ff0a025b2 100644 --- a/internal/backend/remote-state/azure/backend_test.go +++ b/backend/remote-state/azure/backend_test.go @@ -5,8 +5,8 @@ import ( "os" "testing" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/legacy/helper/acctest" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/legacy/helper/acctest" ) func TestBackend_impl(t *testing.T) { diff --git a/internal/backend/remote-state/azure/client.go b/backend/remote-state/azure/client.go similarity index 98% rename from internal/backend/remote-state/azure/client.go rename to backend/remote-state/azure/client.go index 5d22767954b8..9982d184dea5 100644 --- a/internal/backend/remote-state/azure/client.go +++ b/backend/remote-state/azure/client.go @@ -10,8 +10,8 @@ import ( "github.com/hashicorp/go-multierror" "github.com/hashicorp/go-uuid" - "github.com/hashicorp/terraform/internal/states/remote" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/states/remote" + "github.com/hashicorp/terraform/states/statemgr" "github.com/tombuildsstuff/giovanni/storage/2018-11-09/blob/blobs" ) diff --git a/internal/backend/remote-state/azure/client_test.go b/backend/remote-state/azure/client_test.go similarity index 98% rename from internal/backend/remote-state/azure/client_test.go rename to backend/remote-state/azure/client_test.go index 5cc5d6a8467f..bc9283a31b1f 100644 --- a/internal/backend/remote-state/azure/client_test.go +++ b/backend/remote-state/azure/client_test.go @@ -5,9 +5,9 @@ import ( "os" "testing" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/legacy/helper/acctest" - "github.com/hashicorp/terraform/internal/states/remote" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/legacy/helper/acctest" + "github.com/hashicorp/terraform/states/remote" "github.com/tombuildsstuff/giovanni/storage/2018-11-09/blob/blobs" ) diff --git a/internal/backend/remote-state/azure/helpers_test.go b/backend/remote-state/azure/helpers_test.go similarity index 100% rename from internal/backend/remote-state/azure/helpers_test.go rename to backend/remote-state/azure/helpers_test.go diff --git a/internal/backend/remote-state/azure/sender.go b/backend/remote-state/azure/sender.go similarity index 97% rename from internal/backend/remote-state/azure/sender.go rename to backend/remote-state/azure/sender.go index 958273e83d05..a341b58cd105 100644 --- a/internal/backend/remote-state/azure/sender.go +++ b/backend/remote-state/azure/sender.go @@ -6,7 +6,7 @@ import ( "net/http/httputil" "github.com/Azure/go-autorest/autorest" - "github.com/hashicorp/terraform/internal/logging" + "github.com/hashicorp/terraform/logging" ) func buildSender() autorest.Sender { diff --git a/internal/backend/remote-state/consul/backend.go b/backend/remote-state/consul/backend.go similarity index 97% rename from internal/backend/remote-state/consul/backend.go rename to backend/remote-state/consul/backend.go index 884696981350..9d05ba2b9e86 100644 --- a/internal/backend/remote-state/consul/backend.go +++ b/backend/remote-state/consul/backend.go @@ -7,8 +7,8 @@ import ( "time" consulapi "github.com/hashicorp/consul/api" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/legacy/helper/schema" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/legacy/helper/schema" ) // New creates a new backend for Consul remote state. diff --git a/internal/backend/remote-state/consul/backend_state.go b/backend/remote-state/consul/backend_state.go similarity index 94% rename from internal/backend/remote-state/consul/backend_state.go rename to backend/remote-state/consul/backend_state.go index 98934f3197b5..8601dacdb09c 100644 --- a/internal/backend/remote-state/consul/backend_state.go +++ b/backend/remote-state/consul/backend_state.go @@ -4,10 +4,10 @@ import ( "fmt" "strings" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/remote" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/remote" + "github.com/hashicorp/terraform/states/statemgr" ) const ( diff --git a/internal/backend/remote-state/consul/backend_test.go b/backend/remote-state/consul/backend_test.go similarity index 97% rename from internal/backend/remote-state/consul/backend_test.go rename to backend/remote-state/consul/backend_test.go index 6b6700825aa6..153386c9d62b 100644 --- a/internal/backend/remote-state/consul/backend_test.go +++ b/backend/remote-state/consul/backend_test.go @@ -9,7 +9,7 @@ import ( "time" "github.com/hashicorp/consul/sdk/testutil" - "github.com/hashicorp/terraform/internal/backend" + "github.com/hashicorp/terraform/backend" ) func TestBackend_impl(t *testing.T) { diff --git a/internal/backend/remote-state/consul/client.go b/backend/remote-state/consul/client.go similarity index 99% rename from internal/backend/remote-state/consul/client.go rename to backend/remote-state/consul/client.go index 31dfecb0fd38..5ccc9165981a 100644 --- a/internal/backend/remote-state/consul/client.go +++ b/backend/remote-state/consul/client.go @@ -15,8 +15,8 @@ import ( consulapi "github.com/hashicorp/consul/api" multierror "github.com/hashicorp/go-multierror" - "github.com/hashicorp/terraform/internal/states/remote" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/states/remote" + "github.com/hashicorp/terraform/states/statemgr" ) const ( diff --git a/internal/backend/remote-state/consul/client_test.go b/backend/remote-state/consul/client_test.go similarity index 98% rename from internal/backend/remote-state/consul/client_test.go rename to backend/remote-state/consul/client_test.go index 2a4acf06b9b2..3bf9f1ee002a 100644 --- a/internal/backend/remote-state/consul/client_test.go +++ b/backend/remote-state/consul/client_test.go @@ -13,9 +13,9 @@ import ( "testing" "time" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/states/remote" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/states/remote" + "github.com/hashicorp/terraform/states/statemgr" ) func TestRemoteClient_impl(t *testing.T) { diff --git a/internal/backend/remote-state/cos/backend.go b/backend/remote-state/cos/backend.go similarity index 98% rename from internal/backend/remote-state/cos/backend.go rename to backend/remote-state/cos/backend.go index aebf69aabb89..92ff6c4f6179 100644 --- a/internal/backend/remote-state/cos/backend.go +++ b/backend/remote-state/cos/backend.go @@ -10,8 +10,8 @@ import ( "strings" "time" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/legacy/helper/schema" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/legacy/helper/schema" "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile" sts "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sts/v20180813" diff --git a/internal/backend/remote-state/cos/backend_state.go b/backend/remote-state/cos/backend_state.go similarity index 95% rename from internal/backend/remote-state/cos/backend_state.go rename to backend/remote-state/cos/backend_state.go index 46bd3d3957d6..abf8a0572860 100644 --- a/internal/backend/remote-state/cos/backend_state.go +++ b/backend/remote-state/cos/backend_state.go @@ -7,10 +7,10 @@ import ( "sort" "strings" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/remote" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/remote" + "github.com/hashicorp/terraform/states/statemgr" ) // Define file suffix diff --git a/internal/backend/remote-state/cos/backend_test.go b/backend/remote-state/cos/backend_test.go similarity index 98% rename from internal/backend/remote-state/cos/backend_test.go rename to backend/remote-state/cos/backend_test.go index eb9038ff35f7..fb9894ee8b0f 100644 --- a/internal/backend/remote-state/cos/backend_test.go +++ b/backend/remote-state/cos/backend_test.go @@ -7,8 +7,8 @@ import ( "testing" "time" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/states/remote" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/states/remote" ) const ( diff --git a/internal/backend/remote-state/cos/client.go b/backend/remote-state/cos/client.go similarity index 98% rename from internal/backend/remote-state/cos/client.go rename to backend/remote-state/cos/client.go index 818bc129f5b9..6921dd576806 100644 --- a/internal/backend/remote-state/cos/client.go +++ b/backend/remote-state/cos/client.go @@ -13,8 +13,8 @@ import ( "time" multierror "github.com/hashicorp/go-multierror" - "github.com/hashicorp/terraform/internal/states/remote" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/states/remote" + "github.com/hashicorp/terraform/states/statemgr" tag "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tag/v20180813" "github.com/tencentyun/cos-go-sdk-v5" ) diff --git a/internal/backend/remote-state/cos/transport.go b/backend/remote-state/cos/transport.go similarity index 100% rename from internal/backend/remote-state/cos/transport.go rename to backend/remote-state/cos/transport.go diff --git a/internal/backend/remote-state/gcs/backend.go b/backend/remote-state/gcs/backend.go similarity index 97% rename from internal/backend/remote-state/gcs/backend.go rename to backend/remote-state/gcs/backend.go index 5c6d119238e5..4a5b7df8bcd4 100644 --- a/internal/backend/remote-state/gcs/backend.go +++ b/backend/remote-state/gcs/backend.go @@ -10,9 +10,9 @@ import ( "strings" "cloud.google.com/go/storage" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/httpclient" - "github.com/hashicorp/terraform/internal/legacy/helper/schema" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/httpclient" + "github.com/hashicorp/terraform/legacy/helper/schema" "golang.org/x/oauth2" "google.golang.org/api/impersonate" "google.golang.org/api/option" diff --git a/internal/backend/remote-state/gcs/backend_state.go b/backend/remote-state/gcs/backend_state.go similarity index 94% rename from internal/backend/remote-state/gcs/backend_state.go rename to backend/remote-state/gcs/backend_state.go index 1f1aa8f1b841..e7294e3048a0 100644 --- a/internal/backend/remote-state/gcs/backend_state.go +++ b/backend/remote-state/gcs/backend_state.go @@ -9,10 +9,10 @@ import ( "cloud.google.com/go/storage" "google.golang.org/api/iterator" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/remote" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/remote" + "github.com/hashicorp/terraform/states/statemgr" ) const ( diff --git a/internal/backend/remote-state/gcs/backend_test.go b/backend/remote-state/gcs/backend_test.go similarity index 98% rename from internal/backend/remote-state/gcs/backend_test.go rename to backend/remote-state/gcs/backend_test.go index 9e8ca077c319..6b77bdb86784 100644 --- a/internal/backend/remote-state/gcs/backend_test.go +++ b/backend/remote-state/gcs/backend_test.go @@ -12,9 +12,9 @@ import ( kms "cloud.google.com/go/kms/apiv1" "cloud.google.com/go/storage" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/httpclient" - "github.com/hashicorp/terraform/internal/states/remote" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/httpclient" + "github.com/hashicorp/terraform/states/remote" "google.golang.org/api/option" kmspb "google.golang.org/genproto/googleapis/cloud/kms/v1" ) diff --git a/internal/backend/remote-state/gcs/client.go b/backend/remote-state/gcs/client.go similarity index 97% rename from internal/backend/remote-state/gcs/client.go rename to backend/remote-state/gcs/client.go index b91eaf350755..83bc89e9e742 100644 --- a/internal/backend/remote-state/gcs/client.go +++ b/backend/remote-state/gcs/client.go @@ -8,8 +8,8 @@ import ( "cloud.google.com/go/storage" multierror "github.com/hashicorp/go-multierror" - "github.com/hashicorp/terraform/internal/states/remote" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/states/remote" + "github.com/hashicorp/terraform/states/statemgr" "golang.org/x/net/context" ) diff --git a/internal/backend/remote-state/http/backend.go b/backend/remote-state/http/backend.go similarity index 96% rename from internal/backend/remote-state/http/backend.go rename to backend/remote-state/http/backend.go index 2048294cc36a..addc74ca7071 100644 --- a/internal/backend/remote-state/http/backend.go +++ b/backend/remote-state/http/backend.go @@ -13,11 +13,11 @@ import ( "github.com/hashicorp/go-retryablehttp" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/legacy/helper/schema" - "github.com/hashicorp/terraform/internal/logging" - "github.com/hashicorp/terraform/internal/states/remote" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/legacy/helper/schema" + "github.com/hashicorp/terraform/logging" + "github.com/hashicorp/terraform/states/remote" + "github.com/hashicorp/terraform/states/statemgr" ) func New() backend.Backend { diff --git a/internal/backend/remote-state/http/backend_test.go b/backend/remote-state/http/backend_test.go similarity index 98% rename from internal/backend/remote-state/http/backend_test.go rename to backend/remote-state/http/backend_test.go index 9f32273cbac7..a03ebb319dab 100644 --- a/internal/backend/remote-state/http/backend_test.go +++ b/backend/remote-state/http/backend_test.go @@ -5,10 +5,10 @@ import ( "testing" "time" - "github.com/hashicorp/terraform/internal/configs" + "github.com/hashicorp/terraform/configs" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/backend" + "github.com/hashicorp/terraform/backend" ) func TestBackend_impl(t *testing.T) { diff --git a/internal/backend/remote-state/http/client.go b/backend/remote-state/http/client.go similarity index 98% rename from internal/backend/remote-state/http/client.go rename to backend/remote-state/http/client.go index 71668c0a2d07..3fe75de13684 100644 --- a/internal/backend/remote-state/http/client.go +++ b/backend/remote-state/http/client.go @@ -12,8 +12,8 @@ import ( "net/url" "github.com/hashicorp/go-retryablehttp" - "github.com/hashicorp/terraform/internal/states/remote" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/states/remote" + "github.com/hashicorp/terraform/states/statemgr" ) // httpClient is a remote client that stores data in Consul or HTTP REST. diff --git a/internal/backend/remote-state/http/client_test.go b/backend/remote-state/http/client_test.go similarity index 98% rename from internal/backend/remote-state/http/client_test.go rename to backend/remote-state/http/client_test.go index c8bd121c73dd..c9bce3b78c2c 100644 --- a/internal/backend/remote-state/http/client_test.go +++ b/backend/remote-state/http/client_test.go @@ -11,7 +11,7 @@ import ( "testing" "github.com/hashicorp/go-retryablehttp" - "github.com/hashicorp/terraform/internal/states/remote" + "github.com/hashicorp/terraform/states/remote" ) func TestHTTPClient_impl(t *testing.T) { diff --git a/internal/backend/remote-state/http/mock_server_test.go b/backend/remote-state/http/mock_server_test.go similarity index 100% rename from internal/backend/remote-state/http/mock_server_test.go rename to backend/remote-state/http/mock_server_test.go diff --git a/internal/backend/remote-state/http/server_test.go b/backend/remote-state/http/server_test.go similarity index 98% rename from internal/backend/remote-state/http/server_test.go rename to backend/remote-state/http/server_test.go index ff793708aa08..151234ba040a 100644 --- a/internal/backend/remote-state/http/server_test.go +++ b/backend/remote-state/http/server_test.go @@ -20,10 +20,10 @@ import ( "testing" "github.com/golang/mock/gomock" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/states" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/states" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/backend/remote-state/http/testdata/certs/ca.cert.pem b/backend/remote-state/http/testdata/certs/ca.cert.pem similarity index 100% rename from internal/backend/remote-state/http/testdata/certs/ca.cert.pem rename to backend/remote-state/http/testdata/certs/ca.cert.pem diff --git a/internal/backend/remote-state/http/testdata/certs/ca.key b/backend/remote-state/http/testdata/certs/ca.key similarity index 100% rename from internal/backend/remote-state/http/testdata/certs/ca.key rename to backend/remote-state/http/testdata/certs/ca.key diff --git a/internal/backend/remote-state/http/testdata/certs/client.crt b/backend/remote-state/http/testdata/certs/client.crt similarity index 100% rename from internal/backend/remote-state/http/testdata/certs/client.crt rename to backend/remote-state/http/testdata/certs/client.crt diff --git a/internal/backend/remote-state/http/testdata/certs/client.csr b/backend/remote-state/http/testdata/certs/client.csr similarity index 100% rename from internal/backend/remote-state/http/testdata/certs/client.csr rename to backend/remote-state/http/testdata/certs/client.csr diff --git a/internal/backend/remote-state/http/testdata/certs/client.key b/backend/remote-state/http/testdata/certs/client.key similarity index 100% rename from internal/backend/remote-state/http/testdata/certs/client.key rename to backend/remote-state/http/testdata/certs/client.key diff --git a/internal/backend/remote-state/http/testdata/certs/server.crt b/backend/remote-state/http/testdata/certs/server.crt similarity index 100% rename from internal/backend/remote-state/http/testdata/certs/server.crt rename to backend/remote-state/http/testdata/certs/server.crt diff --git a/internal/backend/remote-state/http/testdata/certs/server.csr b/backend/remote-state/http/testdata/certs/server.csr similarity index 100% rename from internal/backend/remote-state/http/testdata/certs/server.csr rename to backend/remote-state/http/testdata/certs/server.csr diff --git a/internal/backend/remote-state/http/testdata/certs/server.key b/backend/remote-state/http/testdata/certs/server.key similarity index 100% rename from internal/backend/remote-state/http/testdata/certs/server.key rename to backend/remote-state/http/testdata/certs/server.key diff --git a/internal/backend/remote-state/http/testdata/gencerts.sh b/backend/remote-state/http/testdata/gencerts.sh similarity index 100% rename from internal/backend/remote-state/http/testdata/gencerts.sh rename to backend/remote-state/http/testdata/gencerts.sh diff --git a/internal/backend/remote-state/inmem/backend.go b/backend/remote-state/inmem/backend.go similarity index 93% rename from internal/backend/remote-state/inmem/backend.go rename to backend/remote-state/inmem/backend.go index 215dcc41be5e..4689b6971c70 100644 --- a/internal/backend/remote-state/inmem/backend.go +++ b/backend/remote-state/inmem/backend.go @@ -8,11 +8,11 @@ import ( "sync" "time" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/legacy/helper/schema" - statespkg "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/remote" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/legacy/helper/schema" + statespkg "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/remote" + "github.com/hashicorp/terraform/states/statemgr" ) // we keep the states and locks in package-level variables, so that they can be diff --git a/internal/backend/remote-state/inmem/backend_test.go b/backend/remote-state/inmem/backend_test.go similarity index 89% rename from internal/backend/remote-state/inmem/backend_test.go rename to backend/remote-state/inmem/backend_test.go index b7e9a555a906..f401b793d61f 100644 --- a/internal/backend/remote-state/inmem/backend_test.go +++ b/backend/remote-state/inmem/backend_test.go @@ -7,11 +7,11 @@ import ( "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/backend" - statespkg "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/remote" + "github.com/hashicorp/terraform/backend" + statespkg "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/remote" - _ "github.com/hashicorp/terraform/internal/logging" + _ "github.com/hashicorp/terraform/logging" ) func TestMain(m *testing.M) { diff --git a/internal/backend/remote-state/inmem/client.go b/backend/remote-state/inmem/client.go similarity index 86% rename from internal/backend/remote-state/inmem/client.go rename to backend/remote-state/inmem/client.go index 5f404567fd37..21f229bdacf2 100644 --- a/internal/backend/remote-state/inmem/client.go +++ b/backend/remote-state/inmem/client.go @@ -3,8 +3,8 @@ package inmem import ( "crypto/md5" - "github.com/hashicorp/terraform/internal/states/remote" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/states/remote" + "github.com/hashicorp/terraform/states/statemgr" ) // RemoteClient is a remote client that stores data in memory for testing. diff --git a/internal/backend/remote-state/inmem/client_test.go b/backend/remote-state/inmem/client_test.go similarity index 86% rename from internal/backend/remote-state/inmem/client_test.go rename to backend/remote-state/inmem/client_test.go index a9fb56b6e1cc..765eac9ee1d2 100644 --- a/internal/backend/remote-state/inmem/client_test.go +++ b/backend/remote-state/inmem/client_test.go @@ -4,8 +4,8 @@ import ( "testing" "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/states/remote" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/states/remote" ) func TestRemoteClient_impl(t *testing.T) { diff --git a/internal/backend/remote-state/kubernetes/backend.go b/backend/remote-state/kubernetes/backend.go similarity index 99% rename from internal/backend/remote-state/kubernetes/backend.go rename to backend/remote-state/kubernetes/backend.go index 907cda9e246e..3a08d299cab2 100644 --- a/internal/backend/remote-state/kubernetes/backend.go +++ b/backend/remote-state/kubernetes/backend.go @@ -8,8 +8,8 @@ import ( "os" "path/filepath" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/legacy/helper/schema" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/legacy/helper/schema" "github.com/hashicorp/terraform/version" "github.com/mitchellh/go-homedir" k8sSchema "k8s.io/apimachinery/pkg/runtime/schema" diff --git a/internal/backend/remote-state/kubernetes/backend_state.go b/backend/remote-state/kubernetes/backend_state.go similarity index 94% rename from internal/backend/remote-state/kubernetes/backend_state.go rename to backend/remote-state/kubernetes/backend_state.go index 56009bc34692..85a9e23d9547 100644 --- a/internal/backend/remote-state/kubernetes/backend_state.go +++ b/backend/remote-state/kubernetes/backend_state.go @@ -6,10 +6,10 @@ import ( "fmt" "sort" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/remote" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/remote" + "github.com/hashicorp/terraform/states/statemgr" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) diff --git a/internal/backend/remote-state/kubernetes/backend_test.go b/backend/remote-state/kubernetes/backend_test.go similarity index 97% rename from internal/backend/remote-state/kubernetes/backend_test.go rename to backend/remote-state/kubernetes/backend_test.go index e24689f0fb1c..9aa88ecaf321 100644 --- a/internal/backend/remote-state/kubernetes/backend_test.go +++ b/backend/remote-state/kubernetes/backend_test.go @@ -9,8 +9,8 @@ import ( "testing" "time" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/states/statemgr" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) diff --git a/internal/backend/remote-state/kubernetes/client.go b/backend/remote-state/kubernetes/client.go similarity index 98% rename from internal/backend/remote-state/kubernetes/client.go rename to backend/remote-state/kubernetes/client.go index 12447c36e0c7..143fe61c6b34 100644 --- a/internal/backend/remote-state/kubernetes/client.go +++ b/backend/remote-state/kubernetes/client.go @@ -11,8 +11,8 @@ import ( "fmt" "strings" - "github.com/hashicorp/terraform/internal/states/remote" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/states/remote" + "github.com/hashicorp/terraform/states/statemgr" k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" diff --git a/internal/backend/remote-state/kubernetes/client_test.go b/backend/remote-state/kubernetes/client_test.go similarity index 94% rename from internal/backend/remote-state/kubernetes/client_test.go rename to backend/remote-state/kubernetes/client_test.go index 08e615423e54..3026afc2d8ad 100644 --- a/internal/backend/remote-state/kubernetes/client_test.go +++ b/backend/remote-state/kubernetes/client_test.go @@ -3,9 +3,9 @@ package kubernetes import ( "testing" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/states/remote" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/states/remote" + "github.com/hashicorp/terraform/states/statemgr" ) func TestRemoteClient_impl(t *testing.T) { diff --git a/internal/backend/remote-state/oss/backend.go b/backend/remote-state/oss/backend.go similarity index 99% rename from internal/backend/remote-state/oss/backend.go rename to backend/remote-state/oss/backend.go index 468a883298c8..013f5485a18b 100644 --- a/internal/backend/remote-state/oss/backend.go +++ b/backend/remote-state/oss/backend.go @@ -29,8 +29,8 @@ import ( "github.com/jmespath/go-jmespath" "github.com/mitchellh/go-homedir" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/legacy/helper/schema" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/legacy/helper/schema" "github.com/hashicorp/terraform/version" ) diff --git a/internal/backend/remote-state/oss/backend_state.go b/backend/remote-state/oss/backend_state.go similarity index 95% rename from internal/backend/remote-state/oss/backend_state.go rename to backend/remote-state/oss/backend_state.go index c1b6616e5efe..0091100edea0 100644 --- a/internal/backend/remote-state/oss/backend_state.go +++ b/backend/remote-state/oss/backend_state.go @@ -11,10 +11,10 @@ import ( "github.com/aliyun/aliyun-oss-go-sdk/oss" "github.com/aliyun/aliyun-tablestore-go-sdk/tablestore" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/remote" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/remote" + "github.com/hashicorp/terraform/states/statemgr" ) const ( diff --git a/internal/backend/remote-state/oss/backend_test.go b/backend/remote-state/oss/backend_test.go similarity index 98% rename from internal/backend/remote-state/oss/backend_test.go rename to backend/remote-state/oss/backend_test.go index e9bc8871639e..7144837e4c79 100644 --- a/internal/backend/remote-state/oss/backend_test.go +++ b/backend/remote-state/oss/backend_test.go @@ -11,8 +11,8 @@ import ( "github.com/aliyun/aliyun-oss-go-sdk/oss" "github.com/aliyun/aliyun-tablestore-go-sdk/tablestore" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/configs/hcl2shim" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/configs/hcl2shim" ) // verify that we are doing ACC tests or the OSS tests specifically diff --git a/internal/backend/remote-state/oss/client.go b/backend/remote-state/oss/client.go similarity index 98% rename from internal/backend/remote-state/oss/client.go rename to backend/remote-state/oss/client.go index 0c2938d0e6c1..09a96b1897bd 100644 --- a/internal/backend/remote-state/oss/client.go +++ b/backend/remote-state/oss/client.go @@ -16,8 +16,8 @@ import ( uuid "github.com/hashicorp/go-uuid" "github.com/pkg/errors" - "github.com/hashicorp/terraform/internal/states/remote" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/states/remote" + "github.com/hashicorp/terraform/states/statemgr" ) const ( diff --git a/internal/backend/remote-state/oss/client_test.go b/backend/remote-state/oss/client_test.go similarity index 97% rename from internal/backend/remote-state/oss/client_test.go rename to backend/remote-state/oss/client_test.go index 1fc62792be66..49a2d63b61b5 100644 --- a/internal/backend/remote-state/oss/client_test.go +++ b/backend/remote-state/oss/client_test.go @@ -9,10 +9,10 @@ import ( "bytes" "crypto/md5" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/states/remote" - "github.com/hashicorp/terraform/internal/states/statefile" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/states/remote" + "github.com/hashicorp/terraform/states/statefile" + "github.com/hashicorp/terraform/states/statemgr" ) // NOTE: Before running this testcase, please create a OTS instance called 'tf-oss-remote' diff --git a/internal/backend/remote-state/pg/backend.go b/backend/remote-state/pg/backend.go similarity index 96% rename from internal/backend/remote-state/pg/backend.go rename to backend/remote-state/pg/backend.go index cdcfb3a6e462..8f1780a90a35 100644 --- a/internal/backend/remote-state/pg/backend.go +++ b/backend/remote-state/pg/backend.go @@ -5,8 +5,8 @@ import ( "database/sql" "fmt" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/legacy/helper/schema" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/legacy/helper/schema" "github.com/lib/pq" ) diff --git a/internal/backend/remote-state/pg/backend_state.go b/backend/remote-state/pg/backend_state.go similarity index 92% rename from internal/backend/remote-state/pg/backend_state.go rename to backend/remote-state/pg/backend_state.go index a1a5544ddb74..5c364a737ace 100644 --- a/internal/backend/remote-state/pg/backend_state.go +++ b/backend/remote-state/pg/backend_state.go @@ -3,10 +3,10 @@ package pg import ( "fmt" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/remote" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/remote" + "github.com/hashicorp/terraform/states/statemgr" ) func (b *Backend) Workspaces() ([]string, error) { diff --git a/internal/backend/remote-state/pg/backend_test.go b/backend/remote-state/pg/backend_test.go similarity index 98% rename from internal/backend/remote-state/pg/backend_test.go rename to backend/remote-state/pg/backend_test.go index 064c001f5b3b..f7ff018719f7 100644 --- a/internal/backend/remote-state/pg/backend_test.go +++ b/backend/remote-state/pg/backend_test.go @@ -9,9 +9,9 @@ import ( "os" "testing" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/states/remote" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/states/remote" + "github.com/hashicorp/terraform/states/statemgr" "github.com/lib/pq" _ "github.com/lib/pq" ) diff --git a/internal/backend/remote-state/pg/client.go b/backend/remote-state/pg/client.go similarity index 97% rename from internal/backend/remote-state/pg/client.go rename to backend/remote-state/pg/client.go index 7ff9cd2468a1..2c6db19f13cf 100644 --- a/internal/backend/remote-state/pg/client.go +++ b/backend/remote-state/pg/client.go @@ -6,8 +6,8 @@ import ( "fmt" uuid "github.com/hashicorp/go-uuid" - "github.com/hashicorp/terraform/internal/states/remote" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/states/remote" + "github.com/hashicorp/terraform/states/statemgr" _ "github.com/lib/pq" ) diff --git a/internal/backend/remote-state/pg/client_test.go b/backend/remote-state/pg/client_test.go similarity index 94% rename from internal/backend/remote-state/pg/client_test.go rename to backend/remote-state/pg/client_test.go index 7bf21ac8483c..ded47a5d120d 100644 --- a/internal/backend/remote-state/pg/client_test.go +++ b/backend/remote-state/pg/client_test.go @@ -8,8 +8,8 @@ import ( "fmt" "testing" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/states/remote" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/states/remote" ) func TestRemoteClient_impl(t *testing.T) { diff --git a/internal/backend/remote-state/s3/backend.go b/backend/remote-state/s3/backend.go similarity index 98% rename from internal/backend/remote-state/s3/backend.go rename to backend/remote-state/s3/backend.go index c56e390a7f18..2e41e6be5ff2 100644 --- a/internal/backend/remote-state/s3/backend.go +++ b/backend/remote-state/s3/backend.go @@ -11,9 +11,9 @@ import ( "github.com/aws/aws-sdk-go/service/dynamodb" "github.com/aws/aws-sdk-go/service/s3" awsbase "github.com/hashicorp/aws-sdk-go-base" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/legacy/helper/schema" - "github.com/hashicorp/terraform/internal/logging" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/legacy/helper/schema" + "github.com/hashicorp/terraform/logging" "github.com/hashicorp/terraform/version" ) diff --git a/internal/backend/remote-state/s3/backend_state.go b/backend/remote-state/s3/backend_state.go similarity index 95% rename from internal/backend/remote-state/s3/backend_state.go rename to backend/remote-state/s3/backend_state.go index d5505f2733c3..65f4f8363b25 100644 --- a/internal/backend/remote-state/s3/backend_state.go +++ b/backend/remote-state/s3/backend_state.go @@ -11,10 +11,10 @@ import ( "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/s3" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/remote" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/remote" + "github.com/hashicorp/terraform/states/statemgr" ) func (b *Backend) Workspaces() ([]string, error) { diff --git a/internal/backend/remote-state/s3/backend_test.go b/backend/remote-state/s3/backend_test.go similarity index 99% rename from internal/backend/remote-state/s3/backend_test.go rename to backend/remote-state/s3/backend_test.go index 268c44490411..918aeb4e6e88 100644 --- a/internal/backend/remote-state/s3/backend_test.go +++ b/backend/remote-state/s3/backend_test.go @@ -12,10 +12,10 @@ import ( "github.com/aws/aws-sdk-go/service/dynamodb" "github.com/aws/aws-sdk-go/service/s3" awsbase "github.com/hashicorp/aws-sdk-go-base" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/configs/hcl2shim" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/remote" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/configs/hcl2shim" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/remote" ) var ( diff --git a/internal/backend/remote-state/s3/client.go b/backend/remote-state/s3/client.go similarity index 98% rename from internal/backend/remote-state/s3/client.go rename to backend/remote-state/s3/client.go index 75e89a616a37..e1624f04ccc6 100644 --- a/internal/backend/remote-state/s3/client.go +++ b/backend/remote-state/s3/client.go @@ -18,8 +18,8 @@ import ( "github.com/aws/aws-sdk-go/service/s3" multierror "github.com/hashicorp/go-multierror" uuid "github.com/hashicorp/go-uuid" - "github.com/hashicorp/terraform/internal/states/remote" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/states/remote" + "github.com/hashicorp/terraform/states/statemgr" ) // Store the last saved serial in dynamo with this suffix for consistency checks. diff --git a/internal/backend/remote-state/s3/client_test.go b/backend/remote-state/s3/client_test.go similarity index 97% rename from internal/backend/remote-state/s3/client_test.go rename to backend/remote-state/s3/client_test.go index abbd4257c10f..c18f99e3cfa6 100644 --- a/internal/backend/remote-state/s3/client_test.go +++ b/backend/remote-state/s3/client_test.go @@ -8,10 +8,10 @@ import ( "testing" "time" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/states/remote" - "github.com/hashicorp/terraform/internal/states/statefile" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/states/remote" + "github.com/hashicorp/terraform/states/statefile" + "github.com/hashicorp/terraform/states/statemgr" ) func TestRemoteClient_impl(t *testing.T) { diff --git a/internal/backend/remote/backend.go b/backend/remote/backend.go similarity index 98% rename from internal/backend/remote/backend.go rename to backend/remote/backend.go index a26415fdaf6e..b0874de27ddf 100644 --- a/internal/backend/remote/backend.go +++ b/backend/remote/backend.go @@ -16,19 +16,19 @@ import ( version "github.com/hashicorp/go-version" svchost "github.com/hashicorp/terraform-svchost" "github.com/hashicorp/terraform-svchost/disco" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/logging" - "github.com/hashicorp/terraform/internal/states/remote" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/logging" + "github.com/hashicorp/terraform/states/remote" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" tfversion "github.com/hashicorp/terraform/version" "github.com/mitchellh/cli" "github.com/mitchellh/colorstring" "github.com/zclconf/go-cty/cty" - backendLocal "github.com/hashicorp/terraform/internal/backend/local" + backendLocal "github.com/hashicorp/terraform/backend/local" ) const ( diff --git a/internal/backend/remote/backend_apply.go b/backend/remote/backend_apply.go similarity index 97% rename from internal/backend/remote/backend_apply.go rename to backend/remote/backend_apply.go index ef89466a235b..f1782b095bbe 100644 --- a/internal/backend/remote/backend_apply.go +++ b/backend/remote/backend_apply.go @@ -9,10 +9,10 @@ import ( tfe "github.com/hashicorp/go-tfe" version "github.com/hashicorp/go-version" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" ) func (b *Remote) opApply(stopCtx, cancelCtx context.Context, op *backend.Operation, w *tfe.Workspace) (*tfe.Run, error) { diff --git a/internal/backend/remote/backend_apply_test.go b/backend/remote/backend_apply_test.go similarity index 98% rename from internal/backend/remote/backend_apply_test.go rename to backend/remote/backend_apply_test.go index c0e8aef2047f..aaf39c2be6b9 100644 --- a/internal/backend/remote/backend_apply_test.go +++ b/backend/remote/backend_apply_test.go @@ -12,19 +12,19 @@ import ( "github.com/google/go-cmp/cmp" tfe "github.com/hashicorp/go-tfe" version "github.com/hashicorp/go-version" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/cloud" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/clistate" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/depsfile" - "github.com/hashicorp/terraform/internal/initwd" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/plans/planfile" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/terminal" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/cloud" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/clistate" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/depsfile" + "github.com/hashicorp/terraform/initwd" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/plans/planfile" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/terminal" + "github.com/hashicorp/terraform/terraform" tfversion "github.com/hashicorp/terraform/version" "github.com/mitchellh/cli" ) diff --git a/internal/backend/remote/backend_common.go b/backend/remote/backend_common.go similarity index 98% rename from internal/backend/remote/backend_common.go rename to backend/remote/backend_common.go index 710cdfb84fba..116ca95483a2 100644 --- a/internal/backend/remote/backend_common.go +++ b/backend/remote/backend_common.go @@ -12,10 +12,10 @@ import ( "time" tfe "github.com/hashicorp/go-tfe" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/logging" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/logging" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/terraform" ) var ( diff --git a/internal/backend/remote/backend_context.go b/backend/remote/backend_context.go similarity index 97% rename from internal/backend/remote/backend_context.go rename to backend/remote/backend_context.go index 372d1cf3d0bb..181f32735f56 100644 --- a/internal/backend/remote/backend_context.go +++ b/backend/remote/backend_context.go @@ -9,11 +9,11 @@ import ( tfe "github.com/hashicorp/go-tfe" "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/backend/remote/backend_context_test.go b/backend/remote/backend_context_test.go similarity index 96% rename from internal/backend/remote/backend_context_test.go rename to backend/remote/backend_context_test.go index f3a133421aed..d694bf5511e6 100644 --- a/internal/backend/remote/backend_context_test.go +++ b/backend/remote/backend_context_test.go @@ -2,20 +2,20 @@ package remote import ( "context" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" "reflect" "testing" tfe "github.com/hashicorp/go-tfe" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/clistate" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/initwd" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/terminal" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/clistate" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/initwd" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/terminal" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/backend/remote/backend_plan.go b/backend/remote/backend_plan.go similarity index 98% rename from internal/backend/remote/backend_plan.go rename to backend/remote/backend_plan.go index ca74d18b6487..8f4a51d961d3 100644 --- a/internal/backend/remote/backend_plan.go +++ b/backend/remote/backend_plan.go @@ -16,10 +16,10 @@ import ( tfe "github.com/hashicorp/go-tfe" version "github.com/hashicorp/go-version" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/logging" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/logging" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/tfdiags" ) var planConfigurationVersionsPollInterval = 500 * time.Millisecond diff --git a/internal/backend/remote/backend_plan_test.go b/backend/remote/backend_plan_test.go similarity index 98% rename from internal/backend/remote/backend_plan_test.go rename to backend/remote/backend_plan_test.go index 3acf0796dae6..ef94ae27126b 100644 --- a/internal/backend/remote/backend_plan_test.go +++ b/backend/remote/backend_plan_test.go @@ -11,19 +11,19 @@ import ( "github.com/google/go-cmp/cmp" tfe "github.com/hashicorp/go-tfe" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/cloud" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/clistate" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/depsfile" - "github.com/hashicorp/terraform/internal/initwd" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/plans/planfile" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/terminal" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/cloud" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/clistate" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/depsfile" + "github.com/hashicorp/terraform/initwd" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/plans/planfile" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/terminal" + "github.com/hashicorp/terraform/terraform" "github.com/mitchellh/cli" ) diff --git a/internal/backend/remote/backend_state.go b/backend/remote/backend_state.go similarity index 95% rename from internal/backend/remote/backend_state.go rename to backend/remote/backend_state.go index 54cdd0aadb84..223678518d51 100644 --- a/internal/backend/remote/backend_state.go +++ b/backend/remote/backend_state.go @@ -10,10 +10,10 @@ import ( tfe "github.com/hashicorp/go-tfe" - "github.com/hashicorp/terraform/internal/command/jsonstate" - "github.com/hashicorp/terraform/internal/states/remote" - "github.com/hashicorp/terraform/internal/states/statefile" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/command/jsonstate" + "github.com/hashicorp/terraform/states/remote" + "github.com/hashicorp/terraform/states/statefile" + "github.com/hashicorp/terraform/states/statemgr" ) type remoteClient struct { diff --git a/internal/backend/remote/backend_state_test.go b/backend/remote/backend_state_test.go similarity index 83% rename from internal/backend/remote/backend_state_test.go rename to backend/remote/backend_state_test.go index 0503936b8e8f..bb338a28e7b6 100644 --- a/internal/backend/remote/backend_state_test.go +++ b/backend/remote/backend_state_test.go @@ -5,11 +5,11 @@ import ( "os" "testing" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/cloud" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/remote" - "github.com/hashicorp/terraform/internal/states/statefile" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/cloud" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/remote" + "github.com/hashicorp/terraform/states/statefile" ) func TestRemoteClient_impl(t *testing.T) { diff --git a/internal/backend/remote/backend_test.go b/backend/remote/backend_test.go similarity index 99% rename from internal/backend/remote/backend_test.go rename to backend/remote/backend_test.go index f0ad73f7c5b9..5c77c3a5ca7d 100644 --- a/internal/backend/remote/backend_test.go +++ b/backend/remote/backend_test.go @@ -10,12 +10,12 @@ import ( tfe "github.com/hashicorp/go-tfe" version "github.com/hashicorp/go-version" "github.com/hashicorp/terraform-svchost/disco" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/tfdiags" tfversion "github.com/hashicorp/terraform/version" "github.com/zclconf/go-cty/cty" - backendLocal "github.com/hashicorp/terraform/internal/backend/local" + backendLocal "github.com/hashicorp/terraform/backend/local" ) func TestRemote(t *testing.T) { diff --git a/internal/backend/remote/cli.go b/backend/remote/cli.go similarity index 86% rename from internal/backend/remote/cli.go rename to backend/remote/cli.go index 926908360e0e..9a4f24d081c9 100644 --- a/internal/backend/remote/cli.go +++ b/backend/remote/cli.go @@ -1,7 +1,7 @@ package remote import ( - "github.com/hashicorp/terraform/internal/backend" + "github.com/hashicorp/terraform/backend" ) // CLIInit implements backend.CLI diff --git a/internal/backend/remote/colorize.go b/backend/remote/colorize.go similarity index 100% rename from internal/backend/remote/colorize.go rename to backend/remote/colorize.go diff --git a/internal/backend/remote/remote_test.go b/backend/remote/remote_test.go similarity index 88% rename from internal/backend/remote/remote_test.go rename to backend/remote/remote_test.go index f4cc3c5c2837..b5fbfcf5e70c 100644 --- a/internal/backend/remote/remote_test.go +++ b/backend/remote/remote_test.go @@ -6,7 +6,7 @@ import ( "testing" "time" - _ "github.com/hashicorp/terraform/internal/logging" + _ "github.com/hashicorp/terraform/logging" ) func TestMain(m *testing.M) { diff --git a/internal/backend/remote/testdata/apply-destroy/apply.log b/backend/remote/testdata/apply-destroy/apply.log similarity index 100% rename from internal/backend/remote/testdata/apply-destroy/apply.log rename to backend/remote/testdata/apply-destroy/apply.log diff --git a/internal/backend/remote/testdata/apply-destroy/main.tf b/backend/remote/testdata/apply-destroy/main.tf similarity index 100% rename from internal/backend/remote/testdata/apply-destroy/main.tf rename to backend/remote/testdata/apply-destroy/main.tf diff --git a/internal/backend/remote/testdata/apply-destroy/plan.log b/backend/remote/testdata/apply-destroy/plan.log similarity index 100% rename from internal/backend/remote/testdata/apply-destroy/plan.log rename to backend/remote/testdata/apply-destroy/plan.log diff --git a/internal/backend/remote/testdata/apply-no-changes/main.tf b/backend/remote/testdata/apply-no-changes/main.tf similarity index 100% rename from internal/backend/remote/testdata/apply-no-changes/main.tf rename to backend/remote/testdata/apply-no-changes/main.tf diff --git a/internal/backend/remote/testdata/apply-no-changes/plan.log b/backend/remote/testdata/apply-no-changes/plan.log similarity index 100% rename from internal/backend/remote/testdata/apply-no-changes/plan.log rename to backend/remote/testdata/apply-no-changes/plan.log diff --git a/internal/backend/remote/testdata/apply-no-changes/policy.log b/backend/remote/testdata/apply-no-changes/policy.log similarity index 100% rename from internal/backend/remote/testdata/apply-no-changes/policy.log rename to backend/remote/testdata/apply-no-changes/policy.log diff --git a/internal/backend/remote/testdata/apply-policy-hard-failed/main.tf b/backend/remote/testdata/apply-policy-hard-failed/main.tf similarity index 100% rename from internal/backend/remote/testdata/apply-policy-hard-failed/main.tf rename to backend/remote/testdata/apply-policy-hard-failed/main.tf diff --git a/internal/backend/remote/testdata/apply-policy-hard-failed/plan.log b/backend/remote/testdata/apply-policy-hard-failed/plan.log similarity index 100% rename from internal/backend/remote/testdata/apply-policy-hard-failed/plan.log rename to backend/remote/testdata/apply-policy-hard-failed/plan.log diff --git a/internal/backend/remote/testdata/apply-policy-hard-failed/policy.log b/backend/remote/testdata/apply-policy-hard-failed/policy.log similarity index 100% rename from internal/backend/remote/testdata/apply-policy-hard-failed/policy.log rename to backend/remote/testdata/apply-policy-hard-failed/policy.log diff --git a/internal/backend/remote/testdata/apply-policy-passed/apply.log b/backend/remote/testdata/apply-policy-passed/apply.log similarity index 100% rename from internal/backend/remote/testdata/apply-policy-passed/apply.log rename to backend/remote/testdata/apply-policy-passed/apply.log diff --git a/internal/backend/remote/testdata/apply-policy-passed/main.tf b/backend/remote/testdata/apply-policy-passed/main.tf similarity index 100% rename from internal/backend/remote/testdata/apply-policy-passed/main.tf rename to backend/remote/testdata/apply-policy-passed/main.tf diff --git a/internal/backend/remote/testdata/apply-policy-passed/plan.log b/backend/remote/testdata/apply-policy-passed/plan.log similarity index 100% rename from internal/backend/remote/testdata/apply-policy-passed/plan.log rename to backend/remote/testdata/apply-policy-passed/plan.log diff --git a/internal/backend/remote/testdata/apply-policy-passed/policy.log b/backend/remote/testdata/apply-policy-passed/policy.log similarity index 100% rename from internal/backend/remote/testdata/apply-policy-passed/policy.log rename to backend/remote/testdata/apply-policy-passed/policy.log diff --git a/internal/backend/remote/testdata/apply-policy-soft-failed/apply.log b/backend/remote/testdata/apply-policy-soft-failed/apply.log similarity index 100% rename from internal/backend/remote/testdata/apply-policy-soft-failed/apply.log rename to backend/remote/testdata/apply-policy-soft-failed/apply.log diff --git a/internal/backend/remote/testdata/apply-policy-soft-failed/main.tf b/backend/remote/testdata/apply-policy-soft-failed/main.tf similarity index 100% rename from internal/backend/remote/testdata/apply-policy-soft-failed/main.tf rename to backend/remote/testdata/apply-policy-soft-failed/main.tf diff --git a/internal/backend/remote/testdata/apply-policy-soft-failed/plan.log b/backend/remote/testdata/apply-policy-soft-failed/plan.log similarity index 100% rename from internal/backend/remote/testdata/apply-policy-soft-failed/plan.log rename to backend/remote/testdata/apply-policy-soft-failed/plan.log diff --git a/internal/backend/remote/testdata/apply-policy-soft-failed/policy.log b/backend/remote/testdata/apply-policy-soft-failed/policy.log similarity index 100% rename from internal/backend/remote/testdata/apply-policy-soft-failed/policy.log rename to backend/remote/testdata/apply-policy-soft-failed/policy.log diff --git a/internal/backend/remote/testdata/apply-variables/apply.log b/backend/remote/testdata/apply-variables/apply.log similarity index 100% rename from internal/backend/remote/testdata/apply-variables/apply.log rename to backend/remote/testdata/apply-variables/apply.log diff --git a/internal/backend/remote/testdata/apply-variables/main.tf b/backend/remote/testdata/apply-variables/main.tf similarity index 100% rename from internal/backend/remote/testdata/apply-variables/main.tf rename to backend/remote/testdata/apply-variables/main.tf diff --git a/internal/backend/remote/testdata/apply-variables/plan.log b/backend/remote/testdata/apply-variables/plan.log similarity index 100% rename from internal/backend/remote/testdata/apply-variables/plan.log rename to backend/remote/testdata/apply-variables/plan.log diff --git a/internal/backend/remote/testdata/apply-with-error/main.tf b/backend/remote/testdata/apply-with-error/main.tf similarity index 100% rename from internal/backend/remote/testdata/apply-with-error/main.tf rename to backend/remote/testdata/apply-with-error/main.tf diff --git a/internal/backend/remote/testdata/apply-with-error/plan.log b/backend/remote/testdata/apply-with-error/plan.log similarity index 100% rename from internal/backend/remote/testdata/apply-with-error/plan.log rename to backend/remote/testdata/apply-with-error/plan.log diff --git a/internal/backend/remote/testdata/apply/apply.log b/backend/remote/testdata/apply/apply.log similarity index 100% rename from internal/backend/remote/testdata/apply/apply.log rename to backend/remote/testdata/apply/apply.log diff --git a/internal/backend/remote/testdata/apply/main.tf b/backend/remote/testdata/apply/main.tf similarity index 100% rename from internal/backend/remote/testdata/apply/main.tf rename to backend/remote/testdata/apply/main.tf diff --git a/internal/backend/remote/testdata/apply/plan.log b/backend/remote/testdata/apply/plan.log similarity index 100% rename from internal/backend/remote/testdata/apply/plan.log rename to backend/remote/testdata/apply/plan.log diff --git a/internal/backend/remote/testdata/empty/.gitignore b/backend/remote/testdata/empty/.gitignore similarity index 100% rename from internal/backend/remote/testdata/empty/.gitignore rename to backend/remote/testdata/empty/.gitignore diff --git a/internal/backend/remote/testdata/plan-cost-estimation/ce.log b/backend/remote/testdata/plan-cost-estimation/ce.log similarity index 100% rename from internal/backend/remote/testdata/plan-cost-estimation/ce.log rename to backend/remote/testdata/plan-cost-estimation/ce.log diff --git a/internal/backend/remote/testdata/plan-cost-estimation/cost-estimate.log b/backend/remote/testdata/plan-cost-estimation/cost-estimate.log similarity index 100% rename from internal/backend/remote/testdata/plan-cost-estimation/cost-estimate.log rename to backend/remote/testdata/plan-cost-estimation/cost-estimate.log diff --git a/internal/backend/remote/testdata/plan-cost-estimation/main.tf b/backend/remote/testdata/plan-cost-estimation/main.tf similarity index 100% rename from internal/backend/remote/testdata/plan-cost-estimation/main.tf rename to backend/remote/testdata/plan-cost-estimation/main.tf diff --git a/internal/backend/remote/testdata/plan-cost-estimation/plan.log b/backend/remote/testdata/plan-cost-estimation/plan.log similarity index 100% rename from internal/backend/remote/testdata/plan-cost-estimation/plan.log rename to backend/remote/testdata/plan-cost-estimation/plan.log diff --git a/internal/backend/remote/testdata/plan-long-line/main.tf b/backend/remote/testdata/plan-long-line/main.tf similarity index 100% rename from internal/backend/remote/testdata/plan-long-line/main.tf rename to backend/remote/testdata/plan-long-line/main.tf diff --git a/internal/backend/remote/testdata/plan-long-line/plan.log b/backend/remote/testdata/plan-long-line/plan.log similarity index 100% rename from internal/backend/remote/testdata/plan-long-line/plan.log rename to backend/remote/testdata/plan-long-line/plan.log diff --git a/internal/backend/remote/testdata/plan-no-changes/main.tf b/backend/remote/testdata/plan-no-changes/main.tf similarity index 100% rename from internal/backend/remote/testdata/plan-no-changes/main.tf rename to backend/remote/testdata/plan-no-changes/main.tf diff --git a/internal/backend/remote/testdata/plan-no-changes/plan.log b/backend/remote/testdata/plan-no-changes/plan.log similarity index 100% rename from internal/backend/remote/testdata/plan-no-changes/plan.log rename to backend/remote/testdata/plan-no-changes/plan.log diff --git a/internal/backend/remote/testdata/plan-no-changes/policy.log b/backend/remote/testdata/plan-no-changes/policy.log similarity index 100% rename from internal/backend/remote/testdata/plan-no-changes/policy.log rename to backend/remote/testdata/plan-no-changes/policy.log diff --git a/internal/backend/remote/testdata/plan-policy-hard-failed/main.tf b/backend/remote/testdata/plan-policy-hard-failed/main.tf similarity index 100% rename from internal/backend/remote/testdata/plan-policy-hard-failed/main.tf rename to backend/remote/testdata/plan-policy-hard-failed/main.tf diff --git a/internal/backend/remote/testdata/plan-policy-hard-failed/plan.log b/backend/remote/testdata/plan-policy-hard-failed/plan.log similarity index 100% rename from internal/backend/remote/testdata/plan-policy-hard-failed/plan.log rename to backend/remote/testdata/plan-policy-hard-failed/plan.log diff --git a/internal/backend/remote/testdata/plan-policy-hard-failed/policy.log b/backend/remote/testdata/plan-policy-hard-failed/policy.log similarity index 100% rename from internal/backend/remote/testdata/plan-policy-hard-failed/policy.log rename to backend/remote/testdata/plan-policy-hard-failed/policy.log diff --git a/internal/backend/remote/testdata/plan-policy-passed/main.tf b/backend/remote/testdata/plan-policy-passed/main.tf similarity index 100% rename from internal/backend/remote/testdata/plan-policy-passed/main.tf rename to backend/remote/testdata/plan-policy-passed/main.tf diff --git a/internal/backend/remote/testdata/plan-policy-passed/plan.log b/backend/remote/testdata/plan-policy-passed/plan.log similarity index 100% rename from internal/backend/remote/testdata/plan-policy-passed/plan.log rename to backend/remote/testdata/plan-policy-passed/plan.log diff --git a/internal/backend/remote/testdata/plan-policy-passed/policy.log b/backend/remote/testdata/plan-policy-passed/policy.log similarity index 100% rename from internal/backend/remote/testdata/plan-policy-passed/policy.log rename to backend/remote/testdata/plan-policy-passed/policy.log diff --git a/internal/backend/remote/testdata/plan-policy-soft-failed/main.tf b/backend/remote/testdata/plan-policy-soft-failed/main.tf similarity index 100% rename from internal/backend/remote/testdata/plan-policy-soft-failed/main.tf rename to backend/remote/testdata/plan-policy-soft-failed/main.tf diff --git a/internal/backend/remote/testdata/plan-policy-soft-failed/plan.log b/backend/remote/testdata/plan-policy-soft-failed/plan.log similarity index 100% rename from internal/backend/remote/testdata/plan-policy-soft-failed/plan.log rename to backend/remote/testdata/plan-policy-soft-failed/plan.log diff --git a/internal/backend/remote/testdata/plan-policy-soft-failed/policy.log b/backend/remote/testdata/plan-policy-soft-failed/policy.log similarity index 100% rename from internal/backend/remote/testdata/plan-policy-soft-failed/policy.log rename to backend/remote/testdata/plan-policy-soft-failed/policy.log diff --git a/internal/backend/remote/testdata/plan-variables/main.tf b/backend/remote/testdata/plan-variables/main.tf similarity index 100% rename from internal/backend/remote/testdata/plan-variables/main.tf rename to backend/remote/testdata/plan-variables/main.tf diff --git a/internal/backend/remote/testdata/plan-variables/plan.log b/backend/remote/testdata/plan-variables/plan.log similarity index 100% rename from internal/backend/remote/testdata/plan-variables/plan.log rename to backend/remote/testdata/plan-variables/plan.log diff --git a/internal/backend/remote/testdata/plan-with-error/main.tf b/backend/remote/testdata/plan-with-error/main.tf similarity index 100% rename from internal/backend/remote/testdata/plan-with-error/main.tf rename to backend/remote/testdata/plan-with-error/main.tf diff --git a/internal/backend/remote/testdata/plan-with-error/plan.log b/backend/remote/testdata/plan-with-error/plan.log similarity index 100% rename from internal/backend/remote/testdata/plan-with-error/plan.log rename to backend/remote/testdata/plan-with-error/plan.log diff --git a/internal/backend/remote/testdata/plan-with-working-directory/terraform/main.tf b/backend/remote/testdata/plan-with-working-directory/terraform/main.tf similarity index 100% rename from internal/backend/remote/testdata/plan-with-working-directory/terraform/main.tf rename to backend/remote/testdata/plan-with-working-directory/terraform/main.tf diff --git a/internal/backend/remote/testdata/plan-with-working-directory/terraform/plan.log b/backend/remote/testdata/plan-with-working-directory/terraform/plan.log similarity index 100% rename from internal/backend/remote/testdata/plan-with-working-directory/terraform/plan.log rename to backend/remote/testdata/plan-with-working-directory/terraform/plan.log diff --git a/internal/backend/remote/testdata/plan/main.tf b/backend/remote/testdata/plan/main.tf similarity index 100% rename from internal/backend/remote/testdata/plan/main.tf rename to backend/remote/testdata/plan/main.tf diff --git a/internal/backend/remote/testdata/plan/plan.log b/backend/remote/testdata/plan/plan.log similarity index 100% rename from internal/backend/remote/testdata/plan/plan.log rename to backend/remote/testdata/plan/plan.log diff --git a/internal/backend/remote/testdata/variables/main.tf b/backend/remote/testdata/variables/main.tf similarity index 100% rename from internal/backend/remote/testdata/variables/main.tf rename to backend/remote/testdata/variables/main.tf diff --git a/internal/backend/remote/testing.go b/backend/remote/testing.go similarity index 93% rename from internal/backend/remote/testing.go rename to backend/remote/testing.go index 7dbb9e9b2c8c..074c3cd8cacb 100644 --- a/internal/backend/remote/testing.go +++ b/backend/remote/testing.go @@ -14,20 +14,20 @@ import ( svchost "github.com/hashicorp/terraform-svchost" "github.com/hashicorp/terraform-svchost/auth" "github.com/hashicorp/terraform-svchost/disco" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/cloud" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/httpclient" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states/remote" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/cloud" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/httpclient" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/states/remote" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" "github.com/hashicorp/terraform/version" "github.com/mitchellh/cli" "github.com/zclconf/go-cty/cty" - backendLocal "github.com/hashicorp/terraform/internal/backend/local" + backendLocal "github.com/hashicorp/terraform/backend/local" ) const ( diff --git a/internal/backend/testing.go b/backend/testing.go similarity index 97% rename from internal/backend/testing.go rename to backend/testing.go index 3b97e307de5b..fa7034b3edda 100644 --- a/internal/backend/testing.go +++ b/backend/testing.go @@ -9,12 +9,12 @@ import ( "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hcldec" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/hcl2shim" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/hcl2shim" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/tfdiags" ) // TestBackendConfig validates and configures the backend with the diff --git a/internal/backend/unparsed_value.go b/backend/unparsed_value.go similarity index 98% rename from internal/backend/unparsed_value.go rename to backend/unparsed_value.go index e7eadea9a1f8..bb39c5bdf5e6 100644 --- a/internal/backend/unparsed_value.go +++ b/backend/unparsed_value.go @@ -4,9 +4,9 @@ import ( "fmt" "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/backend/unparsed_value_test.go b/backend/unparsed_value_test.go similarity index 98% rename from internal/backend/unparsed_value_test.go rename to backend/unparsed_value_test.go index 8807d243d782..9180dabe18a2 100644 --- a/internal/backend/unparsed_value_test.go +++ b/backend/unparsed_value_test.go @@ -8,9 +8,9 @@ import ( "github.com/hashicorp/hcl/v2" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" ) func TestUnparsedValue(t *testing.T) { diff --git a/internal/builtin/providers/README b/builtin/providers/README similarity index 100% rename from internal/builtin/providers/README rename to builtin/providers/README diff --git a/internal/builtin/providers/terraform/data_source_state.go b/builtin/providers/terraform/data_source_state.go similarity index 95% rename from internal/builtin/providers/terraform/data_source_state.go rename to builtin/providers/terraform/data_source_state.go index f69a835343cc..695c9b10218a 100644 --- a/internal/builtin/providers/terraform/data_source_state.go +++ b/builtin/providers/terraform/data_source_state.go @@ -4,14 +4,14 @@ import ( "fmt" "log" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/backend/remote" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/backend/remote" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/tfdiags" "github.com/zclconf/go-cty/cty" - backendInit "github.com/hashicorp/terraform/internal/backend/init" + backendInit "github.com/hashicorp/terraform/backend/init" ) func dataSourceRemoteStateGetSchema() providers.Schema { diff --git a/internal/builtin/providers/terraform/data_source_state_test.go b/builtin/providers/terraform/data_source_state_test.go similarity index 97% rename from internal/builtin/providers/terraform/data_source_state_test.go rename to builtin/providers/terraform/data_source_state_test.go index cf0e3c2a6b0c..d438285a10bd 100644 --- a/internal/builtin/providers/terraform/data_source_state_test.go +++ b/builtin/providers/terraform/data_source_state_test.go @@ -6,10 +6,10 @@ import ( "testing" "github.com/apparentlymart/go-dump/dump" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/tfdiags" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/builtin/providers/terraform/provider.go b/builtin/providers/terraform/provider.go similarity index 98% rename from internal/builtin/providers/terraform/provider.go rename to builtin/providers/terraform/provider.go index 7c43991753a7..3be80acd462b 100644 --- a/internal/builtin/providers/terraform/provider.go +++ b/builtin/providers/terraform/provider.go @@ -4,7 +4,7 @@ import ( "fmt" "log" - "github.com/hashicorp/terraform/internal/providers" + "github.com/hashicorp/terraform/providers" ) // Provider is an implementation of providers.Interface diff --git a/internal/builtin/providers/terraform/provider_test.go b/builtin/providers/terraform/provider_test.go similarity index 59% rename from internal/builtin/providers/terraform/provider_test.go rename to builtin/providers/terraform/provider_test.go index 5f06e9c3423a..fecf720d2f2f 100644 --- a/internal/builtin/providers/terraform/provider_test.go +++ b/builtin/providers/terraform/provider_test.go @@ -1,7 +1,7 @@ package terraform import ( - backendInit "github.com/hashicorp/terraform/internal/backend/init" + backendInit "github.com/hashicorp/terraform/backend/init" ) func init() { diff --git a/internal/builtin/providers/terraform/resource_data.go b/builtin/providers/terraform/resource_data.go similarity index 96% rename from internal/builtin/providers/terraform/resource_data.go rename to builtin/providers/terraform/resource_data.go index b7b67df82296..fe6c6ce97fb5 100644 --- a/internal/builtin/providers/terraform/resource_data.go +++ b/builtin/providers/terraform/resource_data.go @@ -4,9 +4,9 @@ import ( "fmt" "github.com/hashicorp/go-uuid" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/tfdiags" "github.com/zclconf/go-cty/cty" ctyjson "github.com/zclconf/go-cty/cty/json" ) diff --git a/internal/builtin/providers/terraform/resource_data_test.go b/builtin/providers/terraform/resource_data_test.go similarity index 99% rename from internal/builtin/providers/terraform/resource_data_test.go rename to builtin/providers/terraform/resource_data_test.go index 33deb0ddf199..d1b8930be7b9 100644 --- a/internal/builtin/providers/terraform/resource_data_test.go +++ b/builtin/providers/terraform/resource_data_test.go @@ -4,7 +4,7 @@ import ( "strings" "testing" - "github.com/hashicorp/terraform/internal/providers" + "github.com/hashicorp/terraform/providers" "github.com/zclconf/go-cty/cty" ctyjson "github.com/zclconf/go-cty/cty/json" ) diff --git a/internal/builtin/providers/terraform/testdata/basic.tfstate b/builtin/providers/terraform/testdata/basic.tfstate similarity index 100% rename from internal/builtin/providers/terraform/testdata/basic.tfstate rename to builtin/providers/terraform/testdata/basic.tfstate diff --git a/internal/builtin/providers/terraform/testdata/complex_outputs.tfstate b/builtin/providers/terraform/testdata/complex_outputs.tfstate similarity index 100% rename from internal/builtin/providers/terraform/testdata/complex_outputs.tfstate rename to builtin/providers/terraform/testdata/complex_outputs.tfstate diff --git a/internal/builtin/providers/terraform/testdata/empty.tfstate b/builtin/providers/terraform/testdata/empty.tfstate similarity index 100% rename from internal/builtin/providers/terraform/testdata/empty.tfstate rename to builtin/providers/terraform/testdata/empty.tfstate diff --git a/internal/builtin/providers/terraform/testdata/null_outputs.tfstate b/builtin/providers/terraform/testdata/null_outputs.tfstate similarity index 100% rename from internal/builtin/providers/terraform/testdata/null_outputs.tfstate rename to builtin/providers/terraform/testdata/null_outputs.tfstate diff --git a/internal/builtin/provisioners/file/resource_provisioner.go b/builtin/provisioners/file/resource_provisioner.go similarity index 95% rename from internal/builtin/provisioners/file/resource_provisioner.go rename to builtin/provisioners/file/resource_provisioner.go index 54c2e4a2b1be..68d4580e0d8d 100644 --- a/internal/builtin/provisioners/file/resource_provisioner.go +++ b/builtin/provisioners/file/resource_provisioner.go @@ -7,10 +7,10 @@ import ( "io/ioutil" "os" - "github.com/hashicorp/terraform/internal/communicator" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/provisioners" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/communicator" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/provisioners" + "github.com/hashicorp/terraform/tfdiags" "github.com/mitchellh/go-homedir" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/builtin/provisioners/file/resource_provisioner_test.go b/builtin/provisioners/file/resource_provisioner_test.go similarity index 98% rename from internal/builtin/provisioners/file/resource_provisioner_test.go rename to builtin/provisioners/file/resource_provisioner_test.go index c470743b3444..2e70814af745 100644 --- a/internal/builtin/provisioners/file/resource_provisioner_test.go +++ b/builtin/provisioners/file/resource_provisioner_test.go @@ -4,7 +4,7 @@ import ( "strings" "testing" - "github.com/hashicorp/terraform/internal/provisioners" + "github.com/hashicorp/terraform/provisioners" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/builtin/provisioners/local-exec/resource_provisioner.go b/builtin/provisioners/local-exec/resource_provisioner.go similarity index 97% rename from internal/builtin/provisioners/local-exec/resource_provisioner.go rename to builtin/provisioners/local-exec/resource_provisioner.go index 650472c23e7e..387e9e9d9af6 100644 --- a/internal/builtin/provisioners/local-exec/resource_provisioner.go +++ b/builtin/provisioners/local-exec/resource_provisioner.go @@ -9,9 +9,9 @@ import ( "runtime" "github.com/armon/circbuf" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/provisioners" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/provisioners" + "github.com/hashicorp/terraform/tfdiags" "github.com/mitchellh/go-linereader" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/builtin/provisioners/local-exec/resource_provisioner_test.go b/builtin/provisioners/local-exec/resource_provisioner_test.go similarity index 99% rename from internal/builtin/provisioners/local-exec/resource_provisioner_test.go rename to builtin/provisioners/local-exec/resource_provisioner_test.go index d1560d48ee7a..f10a3ac1e7b6 100644 --- a/internal/builtin/provisioners/local-exec/resource_provisioner_test.go +++ b/builtin/provisioners/local-exec/resource_provisioner_test.go @@ -8,7 +8,7 @@ import ( "testing" "time" - "github.com/hashicorp/terraform/internal/provisioners" + "github.com/hashicorp/terraform/provisioners" "github.com/mitchellh/cli" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/builtin/provisioners/remote-exec/resource_provisioner.go b/builtin/provisioners/remote-exec/resource_provisioner.go similarity index 95% rename from internal/builtin/provisioners/remote-exec/resource_provisioner.go rename to builtin/provisioners/remote-exec/resource_provisioner.go index f8edfb78556c..abb729cd0c37 100644 --- a/internal/builtin/provisioners/remote-exec/resource_provisioner.go +++ b/builtin/provisioners/remote-exec/resource_provisioner.go @@ -11,11 +11,11 @@ import ( "os" "strings" - "github.com/hashicorp/terraform/internal/communicator" - "github.com/hashicorp/terraform/internal/communicator/remote" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/provisioners" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/communicator" + "github.com/hashicorp/terraform/communicator/remote" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/provisioners" + "github.com/hashicorp/terraform/tfdiags" "github.com/mitchellh/go-linereader" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/builtin/provisioners/remote-exec/resource_provisioner_test.go b/builtin/provisioners/remote-exec/resource_provisioner_test.go similarity index 97% rename from internal/builtin/provisioners/remote-exec/resource_provisioner_test.go rename to builtin/provisioners/remote-exec/resource_provisioner_test.go index 549dbf30165c..328ffd787158 100644 --- a/internal/builtin/provisioners/remote-exec/resource_provisioner_test.go +++ b/builtin/provisioners/remote-exec/resource_provisioner_test.go @@ -11,9 +11,9 @@ import ( "strings" - "github.com/hashicorp/terraform/internal/communicator" - "github.com/hashicorp/terraform/internal/communicator/remote" - "github.com/hashicorp/terraform/internal/provisioners" + "github.com/hashicorp/terraform/communicator" + "github.com/hashicorp/terraform/communicator/remote" + "github.com/hashicorp/terraform/provisioners" "github.com/mitchellh/cli" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/builtin/provisioners/remote-exec/testdata/script1.sh b/builtin/provisioners/remote-exec/testdata/script1.sh similarity index 100% rename from internal/builtin/provisioners/remote-exec/testdata/script1.sh rename to builtin/provisioners/remote-exec/testdata/script1.sh diff --git a/checkpoint.go b/checkpoint.go index 31cc29bf7527..5885bb345e7e 100644 --- a/checkpoint.go +++ b/checkpoint.go @@ -6,8 +6,8 @@ import ( "path/filepath" "github.com/hashicorp/go-checkpoint" - "github.com/hashicorp/terraform/internal/command" - "github.com/hashicorp/terraform/internal/command/cliconfig" + "github.com/hashicorp/terraform/command" + "github.com/hashicorp/terraform/command/cliconfig" ) func init() { diff --git a/internal/checks/doc.go b/checks/doc.go similarity index 100% rename from internal/checks/doc.go rename to checks/doc.go diff --git a/internal/checks/state.go b/checks/state.go similarity index 98% rename from internal/checks/state.go rename to checks/state.go index 2d9d7e188dba..4d4cb3dca4b6 100644 --- a/internal/checks/state.go +++ b/checks/state.go @@ -5,8 +5,8 @@ import ( "sort" "sync" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs" ) // State is a container for state tracking of all of the the checks declared in diff --git a/internal/checks/state_init.go b/checks/state_init.go similarity index 95% rename from internal/checks/state_init.go rename to checks/state_init.go index 6714243b5c3b..5b2cadc4faad 100644 --- a/internal/checks/state_init.go +++ b/checks/state_init.go @@ -1,8 +1,8 @@ package checks import ( - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs" ) func initialStatuses(cfg *configs.Config) addrs.Map[addrs.ConfigCheckable, *configCheckableState] { diff --git a/internal/checks/state_report.go b/checks/state_report.go similarity index 98% rename from internal/checks/state_report.go rename to checks/state_report.go index ccf35ac13826..01b9c13a4398 100644 --- a/internal/checks/state_report.go +++ b/checks/state_report.go @@ -3,7 +3,7 @@ package checks import ( "fmt" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) // These are the "Report"-prefixed methods of Checks used by Terraform Core diff --git a/internal/checks/state_test.go b/checks/state_test.go similarity index 97% rename from internal/checks/state_test.go rename to checks/state_test.go index 8c0f0d447fb7..f528f94e2eda 100644 --- a/internal/checks/state_test.go +++ b/checks/state_test.go @@ -5,9 +5,9 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configload" - "github.com/hashicorp/terraform/internal/initwd" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/initwd" ) func TestChecksHappyPath(t *testing.T) { diff --git a/internal/checks/status.go b/checks/status.go similarity index 100% rename from internal/checks/status.go rename to checks/status.go diff --git a/internal/checks/status_string.go b/checks/status_string.go similarity index 100% rename from internal/checks/status_string.go rename to checks/status_string.go diff --git a/internal/checks/testdata/happypath/checks-happypath.tf b/checks/testdata/happypath/checks-happypath.tf similarity index 100% rename from internal/checks/testdata/happypath/checks-happypath.tf rename to checks/testdata/happypath/checks-happypath.tf diff --git a/internal/checks/testdata/happypath/child/checks-happypath-child.tf b/checks/testdata/happypath/child/checks-happypath-child.tf similarity index 100% rename from internal/checks/testdata/happypath/child/checks-happypath-child.tf rename to checks/testdata/happypath/child/checks-happypath-child.tf diff --git a/internal/cloud/backend.go b/cloud/backend.go similarity index 98% rename from internal/cloud/backend.go rename to cloud/backend.go index 4625a4d43140..0ad3490e0ee9 100644 --- a/internal/cloud/backend.go +++ b/cloud/backend.go @@ -22,16 +22,16 @@ import ( "github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty/gocty" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/command/jsonformat" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/command/jsonformat" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" tfversion "github.com/hashicorp/terraform/version" - backendLocal "github.com/hashicorp/terraform/internal/backend/local" + backendLocal "github.com/hashicorp/terraform/backend/local" ) const ( diff --git a/internal/cloud/backend_apply.go b/cloud/backend_apply.go similarity index 96% rename from internal/cloud/backend_apply.go rename to cloud/backend_apply.go index fb43127e8361..cc82980862c5 100644 --- a/internal/cloud/backend_apply.go +++ b/cloud/backend_apply.go @@ -8,11 +8,11 @@ import ( "log" tfe "github.com/hashicorp/go-tfe" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/command/jsonformat" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/command/jsonformat" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" ) func (b *Cloud) opApply(stopCtx, cancelCtx context.Context, op *backend.Operation, w *tfe.Workspace) (*tfe.Run, error) { diff --git a/internal/cloud/backend_apply_test.go b/cloud/backend_apply_test.go similarity index 98% rename from internal/cloud/backend_apply_test.go rename to cloud/backend_apply_test.go index c10d9ed07128..3bffa3b55aad 100644 --- a/internal/cloud/backend_apply_test.go +++ b/cloud/backend_apply_test.go @@ -15,19 +15,19 @@ import ( tfe "github.com/hashicorp/go-tfe" mocks "github.com/hashicorp/go-tfe/mocks" version "github.com/hashicorp/go-version" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/clistate" - "github.com/hashicorp/terraform/internal/command/jsonformat" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/depsfile" - "github.com/hashicorp/terraform/internal/initwd" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/plans/planfile" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/terminal" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/clistate" + "github.com/hashicorp/terraform/command/jsonformat" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/depsfile" + "github.com/hashicorp/terraform/initwd" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/plans/planfile" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/terminal" + "github.com/hashicorp/terraform/terraform" tfversion "github.com/hashicorp/terraform/version" "github.com/mitchellh/cli" ) diff --git a/internal/cloud/backend_cli.go b/cloud/backend_cli.go similarity index 81% rename from internal/cloud/backend_cli.go rename to cloud/backend_cli.go index 21d0399b6c31..afcd61026792 100644 --- a/internal/cloud/backend_cli.go +++ b/cloud/backend_cli.go @@ -1,8 +1,8 @@ package cloud import ( - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/command/jsonformat" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/command/jsonformat" ) // CLIInit implements backend.CLI diff --git a/internal/cloud/backend_colorize.go b/cloud/backend_colorize.go similarity index 100% rename from internal/cloud/backend_colorize.go rename to cloud/backend_colorize.go diff --git a/internal/cloud/backend_common.go b/cloud/backend_common.go similarity index 98% rename from internal/cloud/backend_common.go rename to cloud/backend_common.go index a969d1d9279e..7632cc4a89d2 100644 --- a/internal/cloud/backend_common.go +++ b/cloud/backend_common.go @@ -17,11 +17,11 @@ import ( "github.com/hashicorp/go-retryablehttp" tfe "github.com/hashicorp/go-tfe" "github.com/hashicorp/jsonapi" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/command/jsonformat" - "github.com/hashicorp/terraform/internal/logging" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/command/jsonformat" + "github.com/hashicorp/terraform/logging" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/terraform" ) var ( diff --git a/internal/cloud/backend_context.go b/cloud/backend_context.go similarity index 97% rename from internal/cloud/backend_context.go rename to cloud/backend_context.go index a1236b3663ef..06525b04e487 100644 --- a/internal/cloud/backend_context.go +++ b/cloud/backend_context.go @@ -9,11 +9,11 @@ import ( tfe "github.com/hashicorp/go-tfe" "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/cloud/backend_context_test.go b/cloud/backend_context_test.go similarity index 95% rename from internal/cloud/backend_context_test.go rename to cloud/backend_context_test.go index 635efc88b046..0ad957fcf8dd 100644 --- a/internal/cloud/backend_context_test.go +++ b/cloud/backend_context_test.go @@ -6,16 +6,16 @@ import ( "testing" tfe "github.com/hashicorp/go-tfe" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/clistate" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/initwd" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/terminal" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/clistate" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/initwd" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/terminal" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/cloud/backend_plan.go b/cloud/backend_plan.go similarity index 98% rename from internal/cloud/backend_plan.go rename to cloud/backend_plan.go index b2d465138894..3b2eec74d13d 100644 --- a/internal/cloud/backend_plan.go +++ b/cloud/backend_plan.go @@ -17,10 +17,10 @@ import ( "time" tfe "github.com/hashicorp/go-tfe" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/command/jsonformat" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/command/jsonformat" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/tfdiags" ) var planConfigurationVersionsPollInterval = 500 * time.Millisecond diff --git a/internal/cloud/backend_plan_test.go b/cloud/backend_plan_test.go similarity index 98% rename from internal/cloud/backend_plan_test.go rename to cloud/backend_plan_test.go index a4c1e4998a53..c93c724a3c52 100644 --- a/internal/cloud/backend_plan_test.go +++ b/cloud/backend_plan_test.go @@ -12,19 +12,19 @@ import ( "github.com/google/go-cmp/cmp" tfe "github.com/hashicorp/go-tfe" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/clistate" - "github.com/hashicorp/terraform/internal/command/jsonformat" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/depsfile" - "github.com/hashicorp/terraform/internal/initwd" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/plans/planfile" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/terminal" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/clistate" + "github.com/hashicorp/terraform/command/jsonformat" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/depsfile" + "github.com/hashicorp/terraform/initwd" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/plans/planfile" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/terminal" + "github.com/hashicorp/terraform/terraform" "github.com/mitchellh/cli" ) diff --git a/internal/cloud/backend_refresh_test.go b/cloud/backend_refresh_test.go similarity index 83% rename from internal/cloud/backend_refresh_test.go rename to cloud/backend_refresh_test.go index 3abb93577793..93f909e6c40e 100644 --- a/internal/cloud/backend_refresh_test.go +++ b/cloud/backend_refresh_test.go @@ -6,14 +6,14 @@ import ( "testing" "time" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/clistate" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/initwd" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/terminal" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/clistate" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/initwd" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/terminal" "github.com/mitchellh/cli" ) diff --git a/internal/cloud/backend_taskStage_policyEvaluation.go b/cloud/backend_taskStage_policyEvaluation.go similarity index 100% rename from internal/cloud/backend_taskStage_policyEvaluation.go rename to cloud/backend_taskStage_policyEvaluation.go diff --git a/internal/cloud/backend_taskStage_policyEvaluation_test.go b/cloud/backend_taskStage_policyEvaluation_test.go similarity index 100% rename from internal/cloud/backend_taskStage_policyEvaluation_test.go rename to cloud/backend_taskStage_policyEvaluation_test.go diff --git a/internal/cloud/backend_taskStage_taskResults.go b/cloud/backend_taskStage_taskResults.go similarity index 100% rename from internal/cloud/backend_taskStage_taskResults.go rename to cloud/backend_taskStage_taskResults.go diff --git a/internal/cloud/backend_taskStage_taskResults_test.go b/cloud/backend_taskStage_taskResults_test.go similarity index 100% rename from internal/cloud/backend_taskStage_taskResults_test.go rename to cloud/backend_taskStage_taskResults_test.go diff --git a/internal/cloud/backend_taskStages.go b/cloud/backend_taskStages.go similarity index 99% rename from internal/cloud/backend_taskStages.go rename to cloud/backend_taskStages.go index 693572daf2b6..0b8887b9021c 100644 --- a/internal/cloud/backend_taskStages.go +++ b/cloud/backend_taskStages.go @@ -7,7 +7,7 @@ import ( "github.com/hashicorp/go-multierror" tfe "github.com/hashicorp/go-tfe" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/terraform" ) type taskStages map[tfe.Stage]*tfe.TaskStage diff --git a/internal/cloud/backend_taskStages_test.go b/cloud/backend_taskStages_test.go similarity index 100% rename from internal/cloud/backend_taskStages_test.go rename to cloud/backend_taskStages_test.go diff --git a/internal/cloud/backend_test.go b/cloud/backend_test.go similarity index 99% rename from internal/cloud/backend_test.go rename to cloud/backend_test.go index 081fce650570..e5209f1126d3 100644 --- a/internal/cloud/backend_test.go +++ b/cloud/backend_test.go @@ -10,12 +10,12 @@ import ( tfe "github.com/hashicorp/go-tfe" version "github.com/hashicorp/go-version" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/tfdiags" tfversion "github.com/hashicorp/terraform/version" "github.com/zclconf/go-cty/cty" - backendLocal "github.com/hashicorp/terraform/internal/backend/local" + backendLocal "github.com/hashicorp/terraform/backend/local" ) func TestCloud(t *testing.T) { diff --git a/internal/cloud/cloud_integration.go b/cloud/cloud_integration.go similarity index 98% rename from internal/cloud/cloud_integration.go rename to cloud/cloud_integration.go index cd1c6be96aed..8a74197a0899 100644 --- a/internal/cloud/cloud_integration.go +++ b/cloud/cloud_integration.go @@ -7,7 +7,7 @@ import ( "time" "github.com/hashicorp/go-tfe" - "github.com/hashicorp/terraform/internal/backend" + "github.com/hashicorp/terraform/backend" "github.com/mitchellh/cli" ) diff --git a/internal/cloud/cloud_variables.go b/cloud/cloud_variables.go similarity index 88% rename from internal/cloud/cloud_variables.go rename to cloud/cloud_variables.go index af6d6afcfbc1..253b873a85d7 100644 --- a/internal/cloud/cloud_variables.go +++ b/cloud/cloud_variables.go @@ -2,10 +2,10 @@ package cloud import ( "github.com/hashicorp/hcl/v2/hclwrite" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" ) func allowedSourceType(source terraform.ValueSourceType) bool { diff --git a/internal/cloud/cloud_variables_test.go b/cloud/cloud_variables_test.go similarity index 97% rename from internal/cloud/cloud_variables_test.go rename to cloud/cloud_variables_test.go index 9780f788c154..bdaa4e4d00ea 100644 --- a/internal/cloud/cloud_variables_test.go +++ b/cloud/cloud_variables_test.go @@ -5,10 +5,10 @@ import ( "github.com/google/go-cmp/cmp" "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/cloud/configchangemode_string.go b/cloud/configchangemode_string.go similarity index 100% rename from internal/cloud/configchangemode_string.go rename to cloud/configchangemode_string.go diff --git a/internal/cloud/e2e/README.md b/cloud/e2e/README.md similarity index 100% rename from internal/cloud/e2e/README.md rename to cloud/e2e/README.md diff --git a/internal/cloud/e2e/apply_auto_approve_test.go b/cloud/e2e/apply_auto_approve_test.go similarity index 100% rename from internal/cloud/e2e/apply_auto_approve_test.go rename to cloud/e2e/apply_auto_approve_test.go diff --git a/internal/cloud/e2e/apply_no_input_flag_test.go b/cloud/e2e/apply_no_input_flag_test.go similarity index 100% rename from internal/cloud/e2e/apply_no_input_flag_test.go rename to cloud/e2e/apply_no_input_flag_test.go diff --git a/internal/cloud/e2e/backend_apply_before_init_test.go b/cloud/e2e/backend_apply_before_init_test.go similarity index 100% rename from internal/cloud/e2e/backend_apply_before_init_test.go rename to cloud/e2e/backend_apply_before_init_test.go diff --git a/internal/cloud/e2e/env_variables_test.go b/cloud/e2e/env_variables_test.go similarity index 100% rename from internal/cloud/e2e/env_variables_test.go rename to cloud/e2e/env_variables_test.go diff --git a/internal/cloud/e2e/helper_test.go b/cloud/e2e/helper_test.go similarity index 100% rename from internal/cloud/e2e/helper_test.go rename to cloud/e2e/helper_test.go diff --git a/internal/cloud/e2e/init_with_empty_tags_test.go b/cloud/e2e/init_with_empty_tags_test.go similarity index 100% rename from internal/cloud/e2e/init_with_empty_tags_test.go rename to cloud/e2e/init_with_empty_tags_test.go diff --git a/internal/cloud/e2e/main_test.go b/cloud/e2e/main_test.go similarity index 99% rename from internal/cloud/e2e/main_test.go rename to cloud/e2e/main_test.go index 44fc606395b7..156be1bb41aa 100644 --- a/internal/cloud/e2e/main_test.go +++ b/cloud/e2e/main_test.go @@ -12,7 +12,7 @@ import ( expect "github.com/Netflix/go-expect" tfe "github.com/hashicorp/go-tfe" - "github.com/hashicorp/terraform/internal/e2e" + "github.com/hashicorp/terraform/e2e" tfversion "github.com/hashicorp/terraform/version" ) diff --git a/internal/cloud/e2e/migrate_state_multi_to_tfc_test.go b/cloud/e2e/migrate_state_multi_to_tfc_test.go similarity index 100% rename from internal/cloud/e2e/migrate_state_multi_to_tfc_test.go rename to cloud/e2e/migrate_state_multi_to_tfc_test.go diff --git a/internal/cloud/e2e/migrate_state_remote_backend_to_tfc_test.go b/cloud/e2e/migrate_state_remote_backend_to_tfc_test.go similarity index 100% rename from internal/cloud/e2e/migrate_state_remote_backend_to_tfc_test.go rename to cloud/e2e/migrate_state_remote_backend_to_tfc_test.go diff --git a/internal/cloud/e2e/migrate_state_single_to_tfc_test.go b/cloud/e2e/migrate_state_single_to_tfc_test.go similarity index 100% rename from internal/cloud/e2e/migrate_state_single_to_tfc_test.go rename to cloud/e2e/migrate_state_single_to_tfc_test.go diff --git a/internal/cloud/e2e/migrate_state_tfc_to_other_test.go b/cloud/e2e/migrate_state_tfc_to_other_test.go similarity index 100% rename from internal/cloud/e2e/migrate_state_tfc_to_other_test.go rename to cloud/e2e/migrate_state_tfc_to_other_test.go diff --git a/internal/cloud/e2e/migrate_state_tfc_to_tfc_test.go b/cloud/e2e/migrate_state_tfc_to_tfc_test.go similarity index 100% rename from internal/cloud/e2e/migrate_state_tfc_to_tfc_test.go rename to cloud/e2e/migrate_state_tfc_to_tfc_test.go diff --git a/internal/cloud/e2e/run_variables_test.go b/cloud/e2e/run_variables_test.go similarity index 100% rename from internal/cloud/e2e/run_variables_test.go rename to cloud/e2e/run_variables_test.go diff --git a/internal/cloud/errors.go b/cloud/errors.go similarity index 97% rename from internal/cloud/errors.go rename to cloud/errors.go index cf668516f347..9d133a7865db 100644 --- a/internal/cloud/errors.go +++ b/cloud/errors.go @@ -5,7 +5,7 @@ import ( "fmt" "strings" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/cloud/migration.go b/cloud/migration.go similarity index 97% rename from internal/cloud/migration.go rename to cloud/migration.go index 069d1b28ebfd..1ffda5d23fc2 100644 --- a/internal/cloud/migration.go +++ b/cloud/migration.go @@ -1,8 +1,8 @@ package cloud import ( - "github.com/hashicorp/terraform/internal/configs" - legacy "github.com/hashicorp/terraform/internal/legacy/terraform" + "github.com/hashicorp/terraform/configs" + legacy "github.com/hashicorp/terraform/legacy/terraform" ) // Most of the logic for migrating into and out of "cloud mode" actually lives diff --git a/internal/cloud/migration_test.go b/cloud/migration_test.go similarity index 96% rename from internal/cloud/migration_test.go rename to cloud/migration_test.go index f1ae0f48eca5..a3415dcd34e5 100644 --- a/internal/cloud/migration_test.go +++ b/cloud/migration_test.go @@ -3,8 +3,8 @@ package cloud import ( "testing" - "github.com/hashicorp/terraform/internal/configs" - legacy "github.com/hashicorp/terraform/internal/legacy/terraform" + "github.com/hashicorp/terraform/configs" + legacy "github.com/hashicorp/terraform/legacy/terraform" ) func TestDetectConfigChangeType(t *testing.T) { diff --git a/internal/cloud/remote_test.go b/cloud/remote_test.go similarity index 88% rename from internal/cloud/remote_test.go rename to cloud/remote_test.go index b0c44d60a830..e41bdfd9ce5d 100644 --- a/internal/cloud/remote_test.go +++ b/cloud/remote_test.go @@ -6,7 +6,7 @@ import ( "testing" "time" - _ "github.com/hashicorp/terraform/internal/logging" + _ "github.com/hashicorp/terraform/logging" ) func TestMain(m *testing.M) { diff --git a/internal/cloud/state.go b/cloud/state.go similarity index 97% rename from internal/cloud/state.go rename to cloud/state.go index a0379285a899..eeb0348b02fa 100644 --- a/internal/cloud/state.go +++ b/cloud/state.go @@ -18,12 +18,12 @@ import ( tfe "github.com/hashicorp/go-tfe" uuid "github.com/hashicorp/go-uuid" - "github.com/hashicorp/terraform/internal/command/jsonstate" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/remote" - "github.com/hashicorp/terraform/internal/states/statefile" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/command/jsonstate" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/remote" + "github.com/hashicorp/terraform/states/statefile" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/terraform" ) // State implements the State interfaces in the state package to handle diff --git a/internal/cloud/state_test.go b/cloud/state_test.go similarity index 98% rename from internal/cloud/state_test.go rename to cloud/state_test.go index f03bd15c53e5..71abe6fcdc73 100644 --- a/internal/cloud/state_test.go +++ b/cloud/state_test.go @@ -7,8 +7,8 @@ import ( "testing" tfe "github.com/hashicorp/go-tfe" - "github.com/hashicorp/terraform/internal/states/statefile" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/states/statefile" + "github.com/hashicorp/terraform/states/statemgr" ) func TestState_impl(t *testing.T) { diff --git a/internal/cloud/testdata/.gitignore b/cloud/testdata/.gitignore similarity index 100% rename from internal/cloud/testdata/.gitignore rename to cloud/testdata/.gitignore diff --git a/internal/cloud/testdata/apply-destroy/apply.log b/cloud/testdata/apply-destroy/apply.log similarity index 100% rename from internal/cloud/testdata/apply-destroy/apply.log rename to cloud/testdata/apply-destroy/apply.log diff --git a/internal/cloud/testdata/apply-destroy/main.tf b/cloud/testdata/apply-destroy/main.tf similarity index 100% rename from internal/cloud/testdata/apply-destroy/main.tf rename to cloud/testdata/apply-destroy/main.tf diff --git a/internal/cloud/testdata/apply-destroy/plan.log b/cloud/testdata/apply-destroy/plan.log similarity index 100% rename from internal/cloud/testdata/apply-destroy/plan.log rename to cloud/testdata/apply-destroy/plan.log diff --git a/internal/cloud/testdata/apply-json-with-error/main.tf b/cloud/testdata/apply-json-with-error/main.tf similarity index 100% rename from internal/cloud/testdata/apply-json-with-error/main.tf rename to cloud/testdata/apply-json-with-error/main.tf diff --git a/internal/cloud/testdata/apply-json-with-error/plan-redacted.json b/cloud/testdata/apply-json-with-error/plan-redacted.json similarity index 100% rename from internal/cloud/testdata/apply-json-with-error/plan-redacted.json rename to cloud/testdata/apply-json-with-error/plan-redacted.json diff --git a/internal/cloud/testdata/apply-json-with-error/plan.log b/cloud/testdata/apply-json-with-error/plan.log similarity index 100% rename from internal/cloud/testdata/apply-json-with-error/plan.log rename to cloud/testdata/apply-json-with-error/plan.log diff --git a/internal/cloud/testdata/apply-json-with-outputs/apply.log b/cloud/testdata/apply-json-with-outputs/apply.log similarity index 100% rename from internal/cloud/testdata/apply-json-with-outputs/apply.log rename to cloud/testdata/apply-json-with-outputs/apply.log diff --git a/internal/cloud/testdata/apply-json-with-outputs/main.tf b/cloud/testdata/apply-json-with-outputs/main.tf similarity index 100% rename from internal/cloud/testdata/apply-json-with-outputs/main.tf rename to cloud/testdata/apply-json-with-outputs/main.tf diff --git a/internal/cloud/testdata/apply-json-with-outputs/plan-redacted.json b/cloud/testdata/apply-json-with-outputs/plan-redacted.json similarity index 100% rename from internal/cloud/testdata/apply-json-with-outputs/plan-redacted.json rename to cloud/testdata/apply-json-with-outputs/plan-redacted.json diff --git a/internal/cloud/testdata/apply-json-with-outputs/plan.log b/cloud/testdata/apply-json-with-outputs/plan.log similarity index 100% rename from internal/cloud/testdata/apply-json-with-outputs/plan.log rename to cloud/testdata/apply-json-with-outputs/plan.log diff --git a/internal/cloud/testdata/apply-json-with-provisioner-error/apply.log b/cloud/testdata/apply-json-with-provisioner-error/apply.log similarity index 100% rename from internal/cloud/testdata/apply-json-with-provisioner-error/apply.log rename to cloud/testdata/apply-json-with-provisioner-error/apply.log diff --git a/internal/cloud/testdata/apply-json-with-provisioner-error/main.tf b/cloud/testdata/apply-json-with-provisioner-error/main.tf similarity index 100% rename from internal/cloud/testdata/apply-json-with-provisioner-error/main.tf rename to cloud/testdata/apply-json-with-provisioner-error/main.tf diff --git a/internal/cloud/testdata/apply-json-with-provisioner-error/plan-redacted.json b/cloud/testdata/apply-json-with-provisioner-error/plan-redacted.json similarity index 100% rename from internal/cloud/testdata/apply-json-with-provisioner-error/plan-redacted.json rename to cloud/testdata/apply-json-with-provisioner-error/plan-redacted.json diff --git a/internal/cloud/testdata/apply-json-with-provisioner-error/plan.log b/cloud/testdata/apply-json-with-provisioner-error/plan.log similarity index 100% rename from internal/cloud/testdata/apply-json-with-provisioner-error/plan.log rename to cloud/testdata/apply-json-with-provisioner-error/plan.log diff --git a/internal/cloud/testdata/apply-json-with-provisioner/apply.log b/cloud/testdata/apply-json-with-provisioner/apply.log similarity index 100% rename from internal/cloud/testdata/apply-json-with-provisioner/apply.log rename to cloud/testdata/apply-json-with-provisioner/apply.log diff --git a/internal/cloud/testdata/apply-json-with-provisioner/main.tf b/cloud/testdata/apply-json-with-provisioner/main.tf similarity index 100% rename from internal/cloud/testdata/apply-json-with-provisioner/main.tf rename to cloud/testdata/apply-json-with-provisioner/main.tf diff --git a/internal/cloud/testdata/apply-json-with-provisioner/plan-redacted.json b/cloud/testdata/apply-json-with-provisioner/plan-redacted.json similarity index 100% rename from internal/cloud/testdata/apply-json-with-provisioner/plan-redacted.json rename to cloud/testdata/apply-json-with-provisioner/plan-redacted.json diff --git a/internal/cloud/testdata/apply-json-with-provisioner/plan.log b/cloud/testdata/apply-json-with-provisioner/plan.log similarity index 100% rename from internal/cloud/testdata/apply-json-with-provisioner/plan.log rename to cloud/testdata/apply-json-with-provisioner/plan.log diff --git a/internal/cloud/testdata/apply-json/apply.log b/cloud/testdata/apply-json/apply.log similarity index 100% rename from internal/cloud/testdata/apply-json/apply.log rename to cloud/testdata/apply-json/apply.log diff --git a/internal/cloud/testdata/apply-json/main.tf b/cloud/testdata/apply-json/main.tf similarity index 100% rename from internal/cloud/testdata/apply-json/main.tf rename to cloud/testdata/apply-json/main.tf diff --git a/internal/cloud/testdata/apply-json/plan-redacted.json b/cloud/testdata/apply-json/plan-redacted.json similarity index 100% rename from internal/cloud/testdata/apply-json/plan-redacted.json rename to cloud/testdata/apply-json/plan-redacted.json diff --git a/internal/cloud/testdata/apply-json/plan.log b/cloud/testdata/apply-json/plan.log similarity index 100% rename from internal/cloud/testdata/apply-json/plan.log rename to cloud/testdata/apply-json/plan.log diff --git a/internal/cloud/testdata/apply-no-changes/main.tf b/cloud/testdata/apply-no-changes/main.tf similarity index 100% rename from internal/cloud/testdata/apply-no-changes/main.tf rename to cloud/testdata/apply-no-changes/main.tf diff --git a/internal/cloud/testdata/apply-no-changes/plan.log b/cloud/testdata/apply-no-changes/plan.log similarity index 100% rename from internal/cloud/testdata/apply-no-changes/plan.log rename to cloud/testdata/apply-no-changes/plan.log diff --git a/internal/cloud/testdata/apply-no-changes/policy.log b/cloud/testdata/apply-no-changes/policy.log similarity index 100% rename from internal/cloud/testdata/apply-no-changes/policy.log rename to cloud/testdata/apply-no-changes/policy.log diff --git a/internal/cloud/testdata/apply-policy-hard-failed/main.tf b/cloud/testdata/apply-policy-hard-failed/main.tf similarity index 100% rename from internal/cloud/testdata/apply-policy-hard-failed/main.tf rename to cloud/testdata/apply-policy-hard-failed/main.tf diff --git a/internal/cloud/testdata/apply-policy-hard-failed/plan.log b/cloud/testdata/apply-policy-hard-failed/plan.log similarity index 100% rename from internal/cloud/testdata/apply-policy-hard-failed/plan.log rename to cloud/testdata/apply-policy-hard-failed/plan.log diff --git a/internal/cloud/testdata/apply-policy-hard-failed/policy.log b/cloud/testdata/apply-policy-hard-failed/policy.log similarity index 100% rename from internal/cloud/testdata/apply-policy-hard-failed/policy.log rename to cloud/testdata/apply-policy-hard-failed/policy.log diff --git a/internal/cloud/testdata/apply-policy-passed/apply.log b/cloud/testdata/apply-policy-passed/apply.log similarity index 100% rename from internal/cloud/testdata/apply-policy-passed/apply.log rename to cloud/testdata/apply-policy-passed/apply.log diff --git a/internal/cloud/testdata/apply-policy-passed/main.tf b/cloud/testdata/apply-policy-passed/main.tf similarity index 100% rename from internal/cloud/testdata/apply-policy-passed/main.tf rename to cloud/testdata/apply-policy-passed/main.tf diff --git a/internal/cloud/testdata/apply-policy-passed/plan.log b/cloud/testdata/apply-policy-passed/plan.log similarity index 100% rename from internal/cloud/testdata/apply-policy-passed/plan.log rename to cloud/testdata/apply-policy-passed/plan.log diff --git a/internal/cloud/testdata/apply-policy-passed/policy.log b/cloud/testdata/apply-policy-passed/policy.log similarity index 100% rename from internal/cloud/testdata/apply-policy-passed/policy.log rename to cloud/testdata/apply-policy-passed/policy.log diff --git a/internal/cloud/testdata/apply-policy-soft-failed/apply.log b/cloud/testdata/apply-policy-soft-failed/apply.log similarity index 100% rename from internal/cloud/testdata/apply-policy-soft-failed/apply.log rename to cloud/testdata/apply-policy-soft-failed/apply.log diff --git a/internal/cloud/testdata/apply-policy-soft-failed/main.tf b/cloud/testdata/apply-policy-soft-failed/main.tf similarity index 100% rename from internal/cloud/testdata/apply-policy-soft-failed/main.tf rename to cloud/testdata/apply-policy-soft-failed/main.tf diff --git a/internal/cloud/testdata/apply-policy-soft-failed/plan.log b/cloud/testdata/apply-policy-soft-failed/plan.log similarity index 100% rename from internal/cloud/testdata/apply-policy-soft-failed/plan.log rename to cloud/testdata/apply-policy-soft-failed/plan.log diff --git a/internal/cloud/testdata/apply-policy-soft-failed/policy.log b/cloud/testdata/apply-policy-soft-failed/policy.log similarity index 100% rename from internal/cloud/testdata/apply-policy-soft-failed/policy.log rename to cloud/testdata/apply-policy-soft-failed/policy.log diff --git a/internal/cloud/testdata/apply-variables/apply.log b/cloud/testdata/apply-variables/apply.log similarity index 100% rename from internal/cloud/testdata/apply-variables/apply.log rename to cloud/testdata/apply-variables/apply.log diff --git a/internal/cloud/testdata/apply-variables/main.tf b/cloud/testdata/apply-variables/main.tf similarity index 100% rename from internal/cloud/testdata/apply-variables/main.tf rename to cloud/testdata/apply-variables/main.tf diff --git a/internal/cloud/testdata/apply-variables/plan.log b/cloud/testdata/apply-variables/plan.log similarity index 100% rename from internal/cloud/testdata/apply-variables/plan.log rename to cloud/testdata/apply-variables/plan.log diff --git a/internal/cloud/testdata/apply-with-error/main.tf b/cloud/testdata/apply-with-error/main.tf similarity index 100% rename from internal/cloud/testdata/apply-with-error/main.tf rename to cloud/testdata/apply-with-error/main.tf diff --git a/internal/cloud/testdata/apply-with-error/plan.log b/cloud/testdata/apply-with-error/plan.log similarity index 100% rename from internal/cloud/testdata/apply-with-error/plan.log rename to cloud/testdata/apply-with-error/plan.log diff --git a/internal/cloud/testdata/apply/apply.log b/cloud/testdata/apply/apply.log similarity index 100% rename from internal/cloud/testdata/apply/apply.log rename to cloud/testdata/apply/apply.log diff --git a/internal/cloud/testdata/apply/main.tf b/cloud/testdata/apply/main.tf similarity index 100% rename from internal/cloud/testdata/apply/main.tf rename to cloud/testdata/apply/main.tf diff --git a/internal/cloud/testdata/apply/plan.log b/cloud/testdata/apply/plan.log similarity index 100% rename from internal/cloud/testdata/apply/plan.log rename to cloud/testdata/apply/plan.log diff --git a/internal/cloud/testdata/empty/.gitignore b/cloud/testdata/empty/.gitignore similarity index 100% rename from internal/cloud/testdata/empty/.gitignore rename to cloud/testdata/empty/.gitignore diff --git a/internal/cloud/testdata/plan-cost-estimation/ce.log b/cloud/testdata/plan-cost-estimation/ce.log similarity index 100% rename from internal/cloud/testdata/plan-cost-estimation/ce.log rename to cloud/testdata/plan-cost-estimation/ce.log diff --git a/internal/cloud/testdata/plan-cost-estimation/cost-estimate.log b/cloud/testdata/plan-cost-estimation/cost-estimate.log similarity index 100% rename from internal/cloud/testdata/plan-cost-estimation/cost-estimate.log rename to cloud/testdata/plan-cost-estimation/cost-estimate.log diff --git a/internal/cloud/testdata/plan-cost-estimation/main.tf b/cloud/testdata/plan-cost-estimation/main.tf similarity index 100% rename from internal/cloud/testdata/plan-cost-estimation/main.tf rename to cloud/testdata/plan-cost-estimation/main.tf diff --git a/internal/cloud/testdata/plan-cost-estimation/plan.log b/cloud/testdata/plan-cost-estimation/plan.log similarity index 100% rename from internal/cloud/testdata/plan-cost-estimation/plan.log rename to cloud/testdata/plan-cost-estimation/plan.log diff --git a/internal/cloud/testdata/plan-json-basic/main.tf b/cloud/testdata/plan-json-basic/main.tf similarity index 100% rename from internal/cloud/testdata/plan-json-basic/main.tf rename to cloud/testdata/plan-json-basic/main.tf diff --git a/internal/cloud/testdata/plan-json-basic/plan-redacted.json b/cloud/testdata/plan-json-basic/plan-redacted.json similarity index 100% rename from internal/cloud/testdata/plan-json-basic/plan-redacted.json rename to cloud/testdata/plan-json-basic/plan-redacted.json diff --git a/internal/cloud/testdata/plan-json-basic/plan.log b/cloud/testdata/plan-json-basic/plan.log similarity index 100% rename from internal/cloud/testdata/plan-json-basic/plan.log rename to cloud/testdata/plan-json-basic/plan.log diff --git a/internal/cloud/testdata/plan-json-error/main.tf b/cloud/testdata/plan-json-error/main.tf similarity index 100% rename from internal/cloud/testdata/plan-json-error/main.tf rename to cloud/testdata/plan-json-error/main.tf diff --git a/internal/cloud/testdata/plan-json-error/plan-redacted.json b/cloud/testdata/plan-json-error/plan-redacted.json similarity index 100% rename from internal/cloud/testdata/plan-json-error/plan-redacted.json rename to cloud/testdata/plan-json-error/plan-redacted.json diff --git a/internal/cloud/testdata/plan-json-error/plan.log b/cloud/testdata/plan-json-error/plan.log similarity index 100% rename from internal/cloud/testdata/plan-json-error/plan.log rename to cloud/testdata/plan-json-error/plan.log diff --git a/internal/cloud/testdata/plan-json-full/main.tf b/cloud/testdata/plan-json-full/main.tf similarity index 100% rename from internal/cloud/testdata/plan-json-full/main.tf rename to cloud/testdata/plan-json-full/main.tf diff --git a/internal/cloud/testdata/plan-json-full/plan-redacted.json b/cloud/testdata/plan-json-full/plan-redacted.json similarity index 100% rename from internal/cloud/testdata/plan-json-full/plan-redacted.json rename to cloud/testdata/plan-json-full/plan-redacted.json diff --git a/internal/cloud/testdata/plan-json-full/plan.log b/cloud/testdata/plan-json-full/plan.log similarity index 100% rename from internal/cloud/testdata/plan-json-full/plan.log rename to cloud/testdata/plan-json-full/plan.log diff --git a/internal/cloud/testdata/plan-long-line/main.tf b/cloud/testdata/plan-long-line/main.tf similarity index 100% rename from internal/cloud/testdata/plan-long-line/main.tf rename to cloud/testdata/plan-long-line/main.tf diff --git a/internal/cloud/testdata/plan-long-line/plan.log b/cloud/testdata/plan-long-line/plan.log similarity index 100% rename from internal/cloud/testdata/plan-long-line/plan.log rename to cloud/testdata/plan-long-line/plan.log diff --git a/internal/cloud/testdata/plan-no-changes/main.tf b/cloud/testdata/plan-no-changes/main.tf similarity index 100% rename from internal/cloud/testdata/plan-no-changes/main.tf rename to cloud/testdata/plan-no-changes/main.tf diff --git a/internal/cloud/testdata/plan-no-changes/plan.log b/cloud/testdata/plan-no-changes/plan.log similarity index 100% rename from internal/cloud/testdata/plan-no-changes/plan.log rename to cloud/testdata/plan-no-changes/plan.log diff --git a/internal/cloud/testdata/plan-no-changes/policy.log b/cloud/testdata/plan-no-changes/policy.log similarity index 100% rename from internal/cloud/testdata/plan-no-changes/policy.log rename to cloud/testdata/plan-no-changes/policy.log diff --git a/internal/cloud/testdata/plan-policy-hard-failed/main.tf b/cloud/testdata/plan-policy-hard-failed/main.tf similarity index 100% rename from internal/cloud/testdata/plan-policy-hard-failed/main.tf rename to cloud/testdata/plan-policy-hard-failed/main.tf diff --git a/internal/cloud/testdata/plan-policy-hard-failed/plan.log b/cloud/testdata/plan-policy-hard-failed/plan.log similarity index 100% rename from internal/cloud/testdata/plan-policy-hard-failed/plan.log rename to cloud/testdata/plan-policy-hard-failed/plan.log diff --git a/internal/cloud/testdata/plan-policy-hard-failed/policy.log b/cloud/testdata/plan-policy-hard-failed/policy.log similarity index 100% rename from internal/cloud/testdata/plan-policy-hard-failed/policy.log rename to cloud/testdata/plan-policy-hard-failed/policy.log diff --git a/internal/cloud/testdata/plan-policy-passed/main.tf b/cloud/testdata/plan-policy-passed/main.tf similarity index 100% rename from internal/cloud/testdata/plan-policy-passed/main.tf rename to cloud/testdata/plan-policy-passed/main.tf diff --git a/internal/cloud/testdata/plan-policy-passed/plan.log b/cloud/testdata/plan-policy-passed/plan.log similarity index 100% rename from internal/cloud/testdata/plan-policy-passed/plan.log rename to cloud/testdata/plan-policy-passed/plan.log diff --git a/internal/cloud/testdata/plan-policy-passed/policy.log b/cloud/testdata/plan-policy-passed/policy.log similarity index 100% rename from internal/cloud/testdata/plan-policy-passed/policy.log rename to cloud/testdata/plan-policy-passed/policy.log diff --git a/internal/cloud/testdata/plan-policy-soft-failed/main.tf b/cloud/testdata/plan-policy-soft-failed/main.tf similarity index 100% rename from internal/cloud/testdata/plan-policy-soft-failed/main.tf rename to cloud/testdata/plan-policy-soft-failed/main.tf diff --git a/internal/cloud/testdata/plan-policy-soft-failed/plan.log b/cloud/testdata/plan-policy-soft-failed/plan.log similarity index 100% rename from internal/cloud/testdata/plan-policy-soft-failed/plan.log rename to cloud/testdata/plan-policy-soft-failed/plan.log diff --git a/internal/cloud/testdata/plan-policy-soft-failed/policy.log b/cloud/testdata/plan-policy-soft-failed/policy.log similarity index 100% rename from internal/cloud/testdata/plan-policy-soft-failed/policy.log rename to cloud/testdata/plan-policy-soft-failed/policy.log diff --git a/internal/cloud/testdata/plan-variables/main.tf b/cloud/testdata/plan-variables/main.tf similarity index 100% rename from internal/cloud/testdata/plan-variables/main.tf rename to cloud/testdata/plan-variables/main.tf diff --git a/internal/cloud/testdata/plan-variables/plan.log b/cloud/testdata/plan-variables/plan.log similarity index 100% rename from internal/cloud/testdata/plan-variables/plan.log rename to cloud/testdata/plan-variables/plan.log diff --git a/internal/cloud/testdata/plan-with-error/main.tf b/cloud/testdata/plan-with-error/main.tf similarity index 100% rename from internal/cloud/testdata/plan-with-error/main.tf rename to cloud/testdata/plan-with-error/main.tf diff --git a/internal/cloud/testdata/plan-with-error/plan.log b/cloud/testdata/plan-with-error/plan.log similarity index 100% rename from internal/cloud/testdata/plan-with-error/plan.log rename to cloud/testdata/plan-with-error/plan.log diff --git a/internal/cloud/testdata/plan-with-working-directory/terraform/main.tf b/cloud/testdata/plan-with-working-directory/terraform/main.tf similarity index 100% rename from internal/cloud/testdata/plan-with-working-directory/terraform/main.tf rename to cloud/testdata/plan-with-working-directory/terraform/main.tf diff --git a/internal/cloud/testdata/plan-with-working-directory/terraform/plan.log b/cloud/testdata/plan-with-working-directory/terraform/plan.log similarity index 100% rename from internal/cloud/testdata/plan-with-working-directory/terraform/plan.log rename to cloud/testdata/plan-with-working-directory/terraform/plan.log diff --git a/internal/cloud/testdata/plan/main.tf b/cloud/testdata/plan/main.tf similarity index 100% rename from internal/cloud/testdata/plan/main.tf rename to cloud/testdata/plan/main.tf diff --git a/internal/cloud/testdata/plan/plan.log b/cloud/testdata/plan/plan.log similarity index 100% rename from internal/cloud/testdata/plan/plan.log rename to cloud/testdata/plan/plan.log diff --git a/internal/cloud/testdata/refresh/main.tf b/cloud/testdata/refresh/main.tf similarity index 100% rename from internal/cloud/testdata/refresh/main.tf rename to cloud/testdata/refresh/main.tf diff --git a/internal/cloud/testdata/variables/main.tf b/cloud/testdata/variables/main.tf similarity index 100% rename from internal/cloud/testdata/variables/main.tf rename to cloud/testdata/variables/main.tf diff --git a/internal/cloud/testing.go b/cloud/testing.go similarity index 96% rename from internal/cloud/testing.go rename to cloud/testing.go index 4c5302ce4aad..8edc13ae049a 100644 --- a/internal/cloud/testing.go +++ b/cloud/testing.go @@ -20,17 +20,17 @@ import ( "github.com/mitchellh/colorstring" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/command/jsonformat" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/httpclient" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/command/jsonformat" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/httpclient" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" "github.com/hashicorp/terraform/version" - backendLocal "github.com/hashicorp/terraform/internal/backend/local" + backendLocal "github.com/hashicorp/terraform/backend/local" ) const ( diff --git a/internal/cloud/tfe_client_mock.go b/cloud/tfe_client_mock.go similarity index 99% rename from internal/cloud/tfe_client_mock.go rename to cloud/tfe_client_mock.go index 090343fd0b20..5f579ff0e23c 100644 --- a/internal/cloud/tfe_client_mock.go +++ b/cloud/tfe_client_mock.go @@ -19,7 +19,7 @@ import ( tfe "github.com/hashicorp/go-tfe" "github.com/mitchellh/copystructure" - "github.com/hashicorp/terraform/internal/command/jsonformat" + "github.com/hashicorp/terraform/command/jsonformat" tfversion "github.com/hashicorp/terraform/version" ) diff --git a/internal/command/apply.go b/command/apply.go similarity index 97% rename from internal/command/apply.go rename to command/apply.go index 072709472afe..2fbc496cc87b 100644 --- a/internal/command/apply.go +++ b/command/apply.go @@ -4,11 +4,11 @@ import ( "fmt" "strings" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/plans/planfile" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/plans/planfile" + "github.com/hashicorp/terraform/tfdiags" ) // ApplyCommand is a Command implementation that applies a Terraform diff --git a/internal/command/apply_destroy_test.go b/command/apply_destroy_test.go similarity index 98% rename from internal/command/apply_destroy_test.go rename to command/apply_destroy_test.go index 27aaff901723..ee02130f9c65 100644 --- a/internal/command/apply_destroy_test.go +++ b/command/apply_destroy_test.go @@ -9,11 +9,11 @@ import ( "github.com/mitchellh/cli" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/statefile" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/statefile" ) func TestApply_destroy(t *testing.T) { diff --git a/internal/command/apply_test.go b/command/apply_test.go similarity index 99% rename from internal/command/apply_test.go rename to command/apply_test.go index ba75c5e84a5f..7468f20ed105 100644 --- a/internal/command/apply_test.go +++ b/command/apply_test.go @@ -18,14 +18,14 @@ import ( "github.com/mitchellh/cli" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" ) func TestApply(t *testing.T) { diff --git a/internal/command/arguments/apply.go b/command/arguments/apply.go similarity index 97% rename from internal/command/arguments/apply.go rename to command/arguments/apply.go index 4d2e6760555e..267c8e5397d3 100644 --- a/internal/command/arguments/apply.go +++ b/command/arguments/apply.go @@ -3,8 +3,8 @@ package arguments import ( "fmt" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/tfdiags" ) // Apply represents the command-line arguments for the apply command. diff --git a/internal/command/arguments/apply_test.go b/command/arguments/apply_test.go similarity index 99% rename from internal/command/arguments/apply_test.go rename to command/arguments/apply_test.go index 80388338004d..eb23919c6f04 100644 --- a/internal/command/arguments/apply_test.go +++ b/command/arguments/apply_test.go @@ -6,8 +6,8 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/plans" ) func TestParseApply_basicValid(t *testing.T) { diff --git a/internal/command/arguments/default.go b/command/arguments/default.go similarity index 100% rename from internal/command/arguments/default.go rename to command/arguments/default.go diff --git a/internal/command/arguments/extended.go b/command/arguments/extended.go similarity index 98% rename from internal/command/arguments/extended.go rename to command/arguments/extended.go index e698182db942..c4b98336ebd4 100644 --- a/internal/command/arguments/extended.go +++ b/command/arguments/extended.go @@ -7,9 +7,9 @@ import ( "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/tfdiags" ) // DefaultParallelism is the limit Terraform places on total parallel diff --git a/internal/command/arguments/flags.go b/command/arguments/flags.go similarity index 100% rename from internal/command/arguments/flags.go rename to command/arguments/flags.go diff --git a/internal/command/arguments/output.go b/command/arguments/output.go similarity index 97% rename from internal/command/arguments/output.go rename to command/arguments/output.go index debf05dd83b4..f77c283ccc91 100644 --- a/internal/command/arguments/output.go +++ b/command/arguments/output.go @@ -1,7 +1,7 @@ package arguments import ( - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" ) // Output represents the command-line arguments for the output command. diff --git a/internal/command/arguments/output_test.go b/command/arguments/output_test.go similarity index 98% rename from internal/command/arguments/output_test.go rename to command/arguments/output_test.go index cb258081378d..304a156bff55 100644 --- a/internal/command/arguments/output_test.go +++ b/command/arguments/output_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/davecgh/go-spew/spew" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" ) func TestParseOutput_valid(t *testing.T) { diff --git a/internal/command/arguments/plan.go b/command/arguments/plan.go similarity index 97% rename from internal/command/arguments/plan.go rename to command/arguments/plan.go index 2300dc7a5ded..0a93759440bb 100644 --- a/internal/command/arguments/plan.go +++ b/command/arguments/plan.go @@ -1,7 +1,7 @@ package arguments import ( - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" ) // Plan represents the command-line arguments for the plan command. diff --git a/internal/command/arguments/plan_test.go b/command/arguments/plan_test.go similarity index 98% rename from internal/command/arguments/plan_test.go rename to command/arguments/plan_test.go index b547d3f7ab2f..14c72e9fb3e3 100644 --- a/internal/command/arguments/plan_test.go +++ b/command/arguments/plan_test.go @@ -6,8 +6,8 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/plans" ) func TestParsePlan_basicValid(t *testing.T) { diff --git a/internal/command/arguments/refresh.go b/command/arguments/refresh.go similarity index 97% rename from internal/command/arguments/refresh.go rename to command/arguments/refresh.go index bc08d9df4d90..0e35483aa7f8 100644 --- a/internal/command/arguments/refresh.go +++ b/command/arguments/refresh.go @@ -1,7 +1,7 @@ package arguments import ( - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" ) // Refresh represents the command-line arguments for the apply command. diff --git a/internal/command/arguments/refresh_test.go b/command/arguments/refresh_test.go similarity index 98% rename from internal/command/arguments/refresh_test.go rename to command/arguments/refresh_test.go index 3f35053f7bed..6988b77f5161 100644 --- a/internal/command/arguments/refresh_test.go +++ b/command/arguments/refresh_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) func TestParseRefresh_basicValid(t *testing.T) { diff --git a/internal/command/arguments/show.go b/command/arguments/show.go similarity index 96% rename from internal/command/arguments/show.go rename to command/arguments/show.go index 4d95fc1daa7b..7667e295863d 100644 --- a/internal/command/arguments/show.go +++ b/command/arguments/show.go @@ -1,7 +1,7 @@ package arguments import ( - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" ) // Show represents the command-line arguments for the show command. diff --git a/internal/command/arguments/show_test.go b/command/arguments/show_test.go similarity index 97% rename from internal/command/arguments/show_test.go rename to command/arguments/show_test.go index 5088e1a94e5b..ef1c072bcd4a 100644 --- a/internal/command/arguments/show_test.go +++ b/command/arguments/show_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/davecgh/go-spew/spew" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" ) func TestParseShow_valid(t *testing.T) { diff --git a/internal/command/arguments/test.go b/command/arguments/test.go similarity index 97% rename from internal/command/arguments/test.go rename to command/arguments/test.go index 8ffbd4914d54..c49759a8e957 100644 --- a/internal/command/arguments/test.go +++ b/command/arguments/test.go @@ -4,7 +4,7 @@ import ( "flag" "io/ioutil" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" ) // Test represents the command line arguments for the "terraform test" command. diff --git a/internal/command/arguments/test_test.go b/command/arguments/test_test.go similarity index 96% rename from internal/command/arguments/test_test.go rename to command/arguments/test_test.go index 9a1c7fed013a..7cd671a77c6e 100644 --- a/internal/command/arguments/test_test.go +++ b/command/arguments/test_test.go @@ -5,7 +5,7 @@ import ( "github.com/apparentlymart/go-shquot/shquot" "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" ) func TestParseTest(t *testing.T) { diff --git a/internal/command/arguments/types.go b/command/arguments/types.go similarity index 100% rename from internal/command/arguments/types.go rename to command/arguments/types.go diff --git a/internal/command/arguments/validate.go b/command/arguments/validate.go similarity index 96% rename from internal/command/arguments/validate.go rename to command/arguments/validate.go index daadd7ed537c..71b31e09aa93 100644 --- a/internal/command/arguments/validate.go +++ b/command/arguments/validate.go @@ -1,7 +1,7 @@ package arguments import ( - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" ) // Validate represents the command-line arguments for the validate command. diff --git a/internal/command/arguments/validate_test.go b/command/arguments/validate_test.go similarity index 97% rename from internal/command/arguments/validate_test.go rename to command/arguments/validate_test.go index e7440555073b..29b90d16c2d0 100644 --- a/internal/command/arguments/validate_test.go +++ b/command/arguments/validate_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/davecgh/go-spew/spew" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" ) func TestParseValidate_valid(t *testing.T) { diff --git a/internal/command/arguments/view.go b/command/arguments/view.go similarity index 100% rename from internal/command/arguments/view.go rename to command/arguments/view.go diff --git a/internal/command/arguments/view_test.go b/command/arguments/view_test.go similarity index 100% rename from internal/command/arguments/view_test.go rename to command/arguments/view_test.go diff --git a/internal/command/autocomplete.go b/command/autocomplete.go similarity index 100% rename from internal/command/autocomplete.go rename to command/autocomplete.go diff --git a/internal/command/autocomplete_test.go b/command/autocomplete_test.go similarity index 100% rename from internal/command/autocomplete_test.go rename to command/autocomplete_test.go diff --git a/internal/command/cli_ui.go b/command/cli_ui.go similarity index 100% rename from internal/command/cli_ui.go rename to command/cli_ui.go diff --git a/internal/command/cli_ui_test.go b/command/cli_ui_test.go similarity index 100% rename from internal/command/cli_ui_test.go rename to command/cli_ui_test.go diff --git a/internal/command/cliconfig/cliconfig.go b/command/cliconfig/cliconfig.go similarity index 99% rename from internal/command/cliconfig/cliconfig.go rename to command/cliconfig/cliconfig.go index ba86c4027d64..fb15bba8432f 100644 --- a/internal/command/cliconfig/cliconfig.go +++ b/command/cliconfig/cliconfig.go @@ -21,7 +21,7 @@ import ( "github.com/hashicorp/hcl" svchost "github.com/hashicorp/terraform-svchost" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" ) const pluginCacheDirEnvVar = "TF_PLUGIN_CACHE_DIR" diff --git a/internal/command/cliconfig/cliconfig_test.go b/command/cliconfig/cliconfig_test.go similarity index 99% rename from internal/command/cliconfig/cliconfig_test.go rename to command/cliconfig/cliconfig_test.go index c94dae86f2f7..4a6e8175e01b 100644 --- a/internal/command/cliconfig/cliconfig_test.go +++ b/command/cliconfig/cliconfig_test.go @@ -8,7 +8,7 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" ) // This is the directory where our test fixtures are. diff --git a/internal/command/cliconfig/config_unix.go b/command/cliconfig/config_unix.go similarity index 100% rename from internal/command/cliconfig/config_unix.go rename to command/cliconfig/config_unix.go diff --git a/internal/command/cliconfig/config_windows.go b/command/cliconfig/config_windows.go similarity index 100% rename from internal/command/cliconfig/config_windows.go rename to command/cliconfig/config_windows.go diff --git a/internal/command/cliconfig/credentials.go b/command/cliconfig/credentials.go similarity index 99% rename from internal/command/cliconfig/credentials.go rename to command/cliconfig/credentials.go index a85a1b7cd2c6..8332c42ed269 100644 --- a/internal/command/cliconfig/credentials.go +++ b/command/cliconfig/credentials.go @@ -15,9 +15,9 @@ import ( svchost "github.com/hashicorp/terraform-svchost" svcauth "github.com/hashicorp/terraform-svchost/auth" - "github.com/hashicorp/terraform/internal/configs/hcl2shim" - pluginDiscovery "github.com/hashicorp/terraform/internal/plugin/discovery" - "github.com/hashicorp/terraform/internal/replacefile" + "github.com/hashicorp/terraform/configs/hcl2shim" + pluginDiscovery "github.com/hashicorp/terraform/plugin/discovery" + "github.com/hashicorp/terraform/replacefile" ) // credentialsConfigFile returns the path for the special configuration file diff --git a/internal/command/cliconfig/credentials_test.go b/command/cliconfig/credentials_test.go similarity index 100% rename from internal/command/cliconfig/credentials_test.go rename to command/cliconfig/credentials_test.go diff --git a/internal/command/cliconfig/provider_installation.go b/command/cliconfig/provider_installation.go similarity index 98% rename from internal/command/cliconfig/provider_installation.go rename to command/cliconfig/provider_installation.go index 90570e653048..deef74fcc14e 100644 --- a/internal/command/cliconfig/provider_installation.go +++ b/command/cliconfig/provider_installation.go @@ -6,9 +6,9 @@ import ( "github.com/hashicorp/hcl" hclast "github.com/hashicorp/hcl/hcl/ast" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/getproviders" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/getproviders" + "github.com/hashicorp/terraform/tfdiags" ) // ProviderInstallation is the structure of the "provider_installation" diff --git a/internal/command/cliconfig/provider_installation_test.go b/command/cliconfig/provider_installation_test.go similarity index 96% rename from internal/command/cliconfig/provider_installation_test.go rename to command/cliconfig/provider_installation_test.go index cd55c0b6b6f5..14c05786d894 100644 --- a/internal/command/cliconfig/provider_installation_test.go +++ b/command/cliconfig/provider_installation_test.go @@ -5,8 +5,8 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/getproviders" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/getproviders" ) func TestLoadConfig_providerInstallation(t *testing.T) { diff --git a/internal/command/cliconfig/testdata/config b/command/cliconfig/testdata/config similarity index 100% rename from internal/command/cliconfig/testdata/config rename to command/cliconfig/testdata/config diff --git a/internal/command/cliconfig/testdata/config-env b/command/cliconfig/testdata/config-env similarity index 100% rename from internal/command/cliconfig/testdata/config-env rename to command/cliconfig/testdata/config-env diff --git a/internal/command/cliconfig/testdata/credentials b/command/cliconfig/testdata/credentials similarity index 100% rename from internal/command/cliconfig/testdata/credentials rename to command/cliconfig/testdata/credentials diff --git a/internal/command/cliconfig/testdata/hosts b/command/cliconfig/testdata/hosts similarity index 100% rename from internal/command/cliconfig/testdata/hosts rename to command/cliconfig/testdata/hosts diff --git a/internal/command/cliconfig/testdata/provider-installation b/command/cliconfig/testdata/provider-installation similarity index 100% rename from internal/command/cliconfig/testdata/provider-installation rename to command/cliconfig/testdata/provider-installation diff --git a/internal/command/cliconfig/testdata/provider-installation-errors b/command/cliconfig/testdata/provider-installation-errors similarity index 100% rename from internal/command/cliconfig/testdata/provider-installation-errors rename to command/cliconfig/testdata/provider-installation-errors diff --git a/internal/command/cliconfig/testdata/provider-installation.json b/command/cliconfig/testdata/provider-installation.json similarity index 100% rename from internal/command/cliconfig/testdata/provider-installation.json rename to command/cliconfig/testdata/provider-installation.json diff --git a/internal/command/clistate/local_state.go b/command/clistate/local_state.go similarity index 98% rename from internal/command/clistate/local_state.go rename to command/clistate/local_state.go index 7a0102c7025b..8301757097c6 100644 --- a/internal/command/clistate/local_state.go +++ b/command/clistate/local_state.go @@ -12,8 +12,8 @@ import ( "time" multierror "github.com/hashicorp/go-multierror" - "github.com/hashicorp/terraform/internal/legacy/terraform" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/legacy/terraform" + "github.com/hashicorp/terraform/states/statemgr" ) // LocalState manages a state storage that is local to the filesystem. diff --git a/internal/command/clistate/local_state_lock_unix.go b/command/clistate/local_state_lock_unix.go similarity index 100% rename from internal/command/clistate/local_state_lock_unix.go rename to command/clistate/local_state_lock_unix.go diff --git a/internal/command/clistate/local_state_lock_windows.go b/command/clistate/local_state_lock_windows.go similarity index 100% rename from internal/command/clistate/local_state_lock_windows.go rename to command/clistate/local_state_lock_windows.go diff --git a/internal/command/clistate/state.go b/command/clistate/state.go similarity index 95% rename from internal/command/clistate/state.go rename to command/clistate/state.go index a9946b6e6a96..5fd686263d7a 100644 --- a/internal/command/clistate/state.go +++ b/command/clistate/state.go @@ -10,10 +10,10 @@ import ( "sync" "time" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/helper/slowmessage" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/helper/slowmessage" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/tfdiags" ) const ( diff --git a/internal/command/clistate/state_test.go b/command/clistate/state_test.go similarity index 63% rename from internal/command/clistate/state_test.go rename to command/clistate/state_test.go index e0daecdd545c..b7efb0760cd9 100644 --- a/internal/command/clistate/state_test.go +++ b/command/clistate/state_test.go @@ -3,10 +3,10 @@ package clistate import ( "testing" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/terminal" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/terminal" ) func TestUnlock(t *testing.T) { diff --git a/internal/command/command.go b/command/command.go similarity index 100% rename from internal/command/command.go rename to command/command.go diff --git a/internal/command/command_test.go b/command/command_test.go similarity index 96% rename from internal/command/command_test.go rename to command/command_test.go index 7998a554224a..b98e44e63683 100644 --- a/internal/command/command_test.go +++ b/command/command_test.go @@ -23,29 +23,29 @@ import ( svchost "github.com/hashicorp/terraform-svchost" "github.com/hashicorp/terraform-svchost/disco" - "github.com/hashicorp/terraform/internal/addrs" - backendInit "github.com/hashicorp/terraform/internal/backend/init" - backendLocal "github.com/hashicorp/terraform/internal/backend/local" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/command/workdir" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configload" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/copy" - "github.com/hashicorp/terraform/internal/depsfile" - "github.com/hashicorp/terraform/internal/getproviders" - "github.com/hashicorp/terraform/internal/initwd" - legacy "github.com/hashicorp/terraform/internal/legacy/terraform" - _ "github.com/hashicorp/terraform/internal/logging" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/plans/planfile" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/registry" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/statefile" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/terminal" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/addrs" + backendInit "github.com/hashicorp/terraform/backend/init" + backendLocal "github.com/hashicorp/terraform/backend/local" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/command/workdir" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/copy" + "github.com/hashicorp/terraform/depsfile" + "github.com/hashicorp/terraform/getproviders" + "github.com/hashicorp/terraform/initwd" + legacy "github.com/hashicorp/terraform/legacy/terraform" + _ "github.com/hashicorp/terraform/logging" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/plans/planfile" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/registry" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/statefile" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/terminal" + "github.com/hashicorp/terraform/terraform" "github.com/hashicorp/terraform/version" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/command/console.go b/command/console.go similarity index 94% rename from internal/command/console.go rename to command/console.go index b3d83087620f..0b49500048a1 100644 --- a/internal/command/console.go +++ b/command/console.go @@ -6,12 +6,12 @@ import ( "os" "strings" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/repl" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/repl" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" "github.com/mitchellh/cli" ) diff --git a/internal/command/console_interactive.go b/command/console_interactive.go similarity index 95% rename from internal/command/console_interactive.go rename to command/console_interactive.go index 32cc3a9efcce..c1b252760658 100644 --- a/internal/command/console_interactive.go +++ b/command/console_interactive.go @@ -11,7 +11,7 @@ import ( "io" "os" - "github.com/hashicorp/terraform/internal/repl" + "github.com/hashicorp/terraform/repl" "github.com/chzyer/readline" "github.com/mitchellh/cli" diff --git a/internal/command/console_interactive_solaris.go b/command/console_interactive_solaris.go similarity index 89% rename from internal/command/console_interactive_solaris.go rename to command/console_interactive_solaris.go index b6e5d4d73fbb..f218f897f57e 100644 --- a/internal/command/console_interactive_solaris.go +++ b/command/console_interactive_solaris.go @@ -6,7 +6,7 @@ package command import ( "fmt" - "github.com/hashicorp/terraform/internal/repl" + "github.com/hashicorp/terraform/repl" "github.com/mitchellh/cli" ) diff --git a/internal/command/console_test.go b/command/console_test.go similarity index 98% rename from internal/command/console_test.go rename to command/console_test.go index de8060c5b587..2a460b191c8f 100644 --- a/internal/command/console_test.go +++ b/command/console_test.go @@ -7,8 +7,8 @@ import ( "strings" "testing" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/providers" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/providers" "github.com/mitchellh/cli" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/command/e2etest/.gitignore b/command/e2etest/.gitignore similarity index 100% rename from internal/command/e2etest/.gitignore rename to command/e2etest/.gitignore diff --git a/internal/command/e2etest/automation_test.go b/command/e2etest/automation_test.go similarity index 98% rename from internal/command/e2etest/automation_test.go rename to command/e2etest/automation_test.go index 02652927d750..1a462177b33f 100644 --- a/internal/command/e2etest/automation_test.go +++ b/command/e2etest/automation_test.go @@ -7,8 +7,8 @@ import ( "strings" "testing" - "github.com/hashicorp/terraform/internal/e2e" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/e2e" + "github.com/hashicorp/terraform/plans" ) // The tests in this file run through different scenarios recommended in our diff --git a/internal/command/e2etest/doc.go b/command/e2etest/doc.go similarity index 94% rename from internal/command/e2etest/doc.go rename to command/e2etest/doc.go index 056a43aa3ffe..702992f3de7e 100644 --- a/internal/command/e2etest/doc.go +++ b/command/e2etest/doc.go @@ -12,7 +12,7 @@ // These tests can be used in two ways. The simplest way is to just run them // with "go test" as normal: // -// go test -v github.com/hashicorp/terraform/internal/command/e2etest +// go test -v github.com/hashicorp/terraform/command/e2etest // // This will compile on the fly a Terraform binary and run the tests against // it. diff --git a/internal/command/e2etest/init_test.go b/command/e2etest/init_test.go similarity index 99% rename from internal/command/e2etest/init_test.go rename to command/e2etest/init_test.go index b365267d026e..37acac31656b 100644 --- a/internal/command/e2etest/init_test.go +++ b/command/e2etest/init_test.go @@ -11,7 +11,7 @@ import ( "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/e2e" + "github.com/hashicorp/terraform/e2e" ) func TestInitProviders(t *testing.T) { diff --git a/internal/command/e2etest/main_test.go b/command/e2etest/main_test.go similarity index 97% rename from internal/command/e2etest/main_test.go rename to command/e2etest/main_test.go index 3c9ba5a5e1b6..17927c7882f5 100644 --- a/internal/command/e2etest/main_test.go +++ b/command/e2etest/main_test.go @@ -6,7 +6,7 @@ import ( "path/filepath" "testing" - "github.com/hashicorp/terraform/internal/e2e" + "github.com/hashicorp/terraform/e2e" ) var terraformBin string diff --git a/internal/command/e2etest/make-archive.sh b/command/e2etest/make-archive.sh similarity index 100% rename from internal/command/e2etest/make-archive.sh rename to command/e2etest/make-archive.sh diff --git a/internal/command/e2etest/module_archive_test.go b/command/e2etest/module_archive_test.go similarity index 93% rename from internal/command/e2etest/module_archive_test.go rename to command/e2etest/module_archive_test.go index cb6a2979fde9..1a27e89ba836 100644 --- a/internal/command/e2etest/module_archive_test.go +++ b/command/e2etest/module_archive_test.go @@ -5,7 +5,7 @@ import ( "strings" "testing" - "github.com/hashicorp/terraform/internal/e2e" + "github.com/hashicorp/terraform/e2e" ) func TestInitModuleArchive(t *testing.T) { diff --git a/internal/command/e2etest/primary_test.go b/command/e2etest/primary_test.go similarity index 98% rename from internal/command/e2etest/primary_test.go rename to command/e2etest/primary_test.go index bd570dd4ff6c..c3ff04635f49 100644 --- a/internal/command/e2etest/primary_test.go +++ b/command/e2etest/primary_test.go @@ -8,8 +8,8 @@ import ( "testing" "github.com/davecgh/go-spew/spew" - "github.com/hashicorp/terraform/internal/e2e" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/e2e" + "github.com/hashicorp/terraform/plans" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/command/e2etest/provider_dev_test.go b/command/e2etest/provider_dev_test.go similarity index 96% rename from internal/command/e2etest/provider_dev_test.go rename to command/e2etest/provider_dev_test.go index 1f6c9fb0d950..33de4d1b9f84 100644 --- a/internal/command/e2etest/provider_dev_test.go +++ b/command/e2etest/provider_dev_test.go @@ -8,7 +8,7 @@ import ( "strings" "testing" - "github.com/hashicorp/terraform/internal/e2e" + "github.com/hashicorp/terraform/e2e" ) // TestProviderDevOverrides is a test for the special dev_overrides setting @@ -40,7 +40,7 @@ func TestProviderDevOverrides(t *testing.T) { // such as if it stops being buildable into an independent executable. providerExeDir := filepath.Join(tf.WorkDir(), "pkgdir") providerExePrefix := filepath.Join(providerExeDir, "terraform-provider-test_") - providerExe := e2e.GoBuild("github.com/hashicorp/terraform/internal/provider-simple/main", providerExePrefix) + providerExe := e2e.GoBuild("github.com/hashicorp/terraform/provider-simple/main", providerExePrefix) t.Logf("temporary provider executable is %s", providerExe) err := ioutil.WriteFile(filepath.Join(tf.WorkDir(), "dev.tfrc"), []byte(fmt.Sprintf(` diff --git a/internal/command/e2etest/provider_plugin_test.go b/command/e2etest/provider_plugin_test.go similarity index 93% rename from internal/command/e2etest/provider_plugin_test.go rename to command/e2etest/provider_plugin_test.go index 49fa793dc1ad..c3b106bb159d 100644 --- a/internal/command/e2etest/provider_plugin_test.go +++ b/command/e2etest/provider_plugin_test.go @@ -6,8 +6,8 @@ import ( "strings" "testing" - "github.com/hashicorp/terraform/internal/e2e" - "github.com/hashicorp/terraform/internal/getproviders" + "github.com/hashicorp/terraform/e2e" + "github.com/hashicorp/terraform/getproviders" ) // TestProviderProtocols verifies that Terraform can execute provider plugins @@ -30,10 +30,10 @@ func TestProviderProtocols(t *testing.T) { // actually run it. Here will build the simple and simple6 (built with // protocol v6) providers. simple6Provider := filepath.Join(tf.WorkDir(), "terraform-provider-simple6") - simple6ProviderExe := e2e.GoBuild("github.com/hashicorp/terraform/internal/provider-simple-v6/main", simple6Provider) + simple6ProviderExe := e2e.GoBuild("github.com/hashicorp/terraform/provider-simple-v6/main", simple6Provider) simpleProvider := filepath.Join(tf.WorkDir(), "terraform-provider-simple") - simpleProviderExe := e2e.GoBuild("github.com/hashicorp/terraform/internal/provider-simple/main", simpleProvider) + simpleProviderExe := e2e.GoBuild("github.com/hashicorp/terraform/provider-simple/main", simpleProvider) // Move the provider binaries into a directory that we will point terraform // to using the -plugin-dir cli flag. diff --git a/internal/command/e2etest/providers_mirror_test.go b/command/e2etest/providers_mirror_test.go similarity index 98% rename from internal/command/e2etest/providers_mirror_test.go rename to command/e2etest/providers_mirror_test.go index 08c54f4c68fa..296c4d4e683b 100644 --- a/internal/command/e2etest/providers_mirror_test.go +++ b/command/e2etest/providers_mirror_test.go @@ -7,7 +7,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/e2e" + "github.com/hashicorp/terraform/e2e" ) // The tests in this file are for the "terraform providers mirror" command, diff --git a/internal/command/e2etest/providers_tamper_test.go b/command/e2etest/providers_tamper_test.go similarity index 98% rename from internal/command/e2etest/providers_tamper_test.go rename to command/e2etest/providers_tamper_test.go index 0f4e8312205f..f21b4f762200 100644 --- a/internal/command/e2etest/providers_tamper_test.go +++ b/command/e2etest/providers_tamper_test.go @@ -7,8 +7,8 @@ import ( "strings" "testing" - "github.com/hashicorp/terraform/internal/e2e" - "github.com/hashicorp/terraform/internal/getproviders" + "github.com/hashicorp/terraform/e2e" + "github.com/hashicorp/terraform/getproviders" ) // TestProviderTampering tests various ways that the provider plugins in the diff --git a/internal/command/e2etest/provisioner_plugin_test.go b/command/e2etest/provisioner_plugin_test.go similarity index 92% rename from internal/command/e2etest/provisioner_plugin_test.go rename to command/e2etest/provisioner_plugin_test.go index 3f5d312b21c9..db234eb620d8 100644 --- a/internal/command/e2etest/provisioner_plugin_test.go +++ b/command/e2etest/provisioner_plugin_test.go @@ -6,7 +6,7 @@ import ( "strings" "testing" - "github.com/hashicorp/terraform/internal/e2e" + "github.com/hashicorp/terraform/e2e" ) // TestProvisionerPlugin is a test that terraform can execute a 3rd party @@ -34,7 +34,7 @@ func TestProvisionerPlugin(t *testing.T) { // to actually run it. Here will build the local-exec provisioner into a // binary called test-provisioner provisionerExePrefix := filepath.Join(tf.WorkDir(), "terraform-provisioner-test_") - provisionerExe := e2e.GoBuild("github.com/hashicorp/terraform/internal/provisioner-local-exec/main", provisionerExePrefix) + provisionerExe := e2e.GoBuild("github.com/hashicorp/terraform/provisioner-local-exec/main", provisionerExePrefix) // provisioners must use the old binary name format, so rename this binary newExe := filepath.Join(tf.WorkDir(), "terraform-provisioner-test") diff --git a/internal/command/e2etest/provisioner_test.go b/command/e2etest/provisioner_test.go similarity index 95% rename from internal/command/e2etest/provisioner_test.go rename to command/e2etest/provisioner_test.go index 63d53576eb66..27759f124996 100644 --- a/internal/command/e2etest/provisioner_test.go +++ b/command/e2etest/provisioner_test.go @@ -4,7 +4,7 @@ import ( "strings" "testing" - "github.com/hashicorp/terraform/internal/e2e" + "github.com/hashicorp/terraform/e2e" ) // TestProviderDevOverrides is a test that terraform can execute a 3rd party diff --git a/internal/command/e2etest/remote_state_test.go b/command/e2etest/remote_state_test.go similarity index 92% rename from internal/command/e2etest/remote_state_test.go rename to command/e2etest/remote_state_test.go index 16b9d5a3f71b..bbb95067205c 100644 --- a/internal/command/e2etest/remote_state_test.go +++ b/command/e2etest/remote_state_test.go @@ -4,7 +4,7 @@ import ( "path/filepath" "testing" - "github.com/hashicorp/terraform/internal/e2e" + "github.com/hashicorp/terraform/e2e" ) func TestTerraformProviderRead(t *testing.T) { diff --git a/internal/command/e2etest/strip_ansi.go b/command/e2etest/strip_ansi.go similarity index 100% rename from internal/command/e2etest/strip_ansi.go rename to command/e2etest/strip_ansi.go diff --git a/internal/command/e2etest/terraform_test.go b/command/e2etest/terraform_test.go similarity index 93% rename from internal/command/e2etest/terraform_test.go rename to command/e2etest/terraform_test.go index a6e706c3bb01..f139361eeccc 100644 --- a/internal/command/e2etest/terraform_test.go +++ b/command/e2etest/terraform_test.go @@ -5,8 +5,8 @@ import ( "strings" "testing" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/e2e" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/e2e" ) func TestTerraformProviderData(t *testing.T) { diff --git a/internal/command/e2etest/testdata/chdir-option/subdir/main.tf b/command/e2etest/testdata/chdir-option/subdir/main.tf similarity index 100% rename from internal/command/e2etest/testdata/chdir-option/subdir/main.tf rename to command/e2etest/testdata/chdir-option/subdir/main.tf diff --git a/internal/command/e2etest/testdata/custom-provider-install-method/cliconfig.tfrc b/command/e2etest/testdata/custom-provider-install-method/cliconfig.tfrc similarity index 100% rename from internal/command/e2etest/testdata/custom-provider-install-method/cliconfig.tfrc rename to command/e2etest/testdata/custom-provider-install-method/cliconfig.tfrc diff --git a/internal/command/e2etest/testdata/custom-provider-install-method/cliconfig.tfrc.json b/command/e2etest/testdata/custom-provider-install-method/cliconfig.tfrc.json similarity index 100% rename from internal/command/e2etest/testdata/custom-provider-install-method/cliconfig.tfrc.json rename to command/e2etest/testdata/custom-provider-install-method/cliconfig.tfrc.json diff --git a/internal/command/e2etest/testdata/custom-provider-install-method/fs-mirror/example.com/awesomecorp/happycloud/1.2.0/os_arch/terraform-provider-happycloud_v1.2.0 b/command/e2etest/testdata/custom-provider-install-method/fs-mirror/example.com/awesomecorp/happycloud/1.2.0/os_arch/terraform-provider-happycloud_v1.2.0 similarity index 100% rename from internal/command/e2etest/testdata/custom-provider-install-method/fs-mirror/example.com/awesomecorp/happycloud/1.2.0/os_arch/terraform-provider-happycloud_v1.2.0 rename to command/e2etest/testdata/custom-provider-install-method/fs-mirror/example.com/awesomecorp/happycloud/1.2.0/os_arch/terraform-provider-happycloud_v1.2.0 diff --git a/internal/command/e2etest/testdata/custom-provider-install-method/main.tf b/command/e2etest/testdata/custom-provider-install-method/main.tf similarity index 100% rename from internal/command/e2etest/testdata/custom-provider-install-method/main.tf rename to command/e2etest/testdata/custom-provider-install-method/main.tf diff --git a/internal/command/e2etest/testdata/empty/.exists b/command/e2etest/testdata/empty/.exists similarity index 100% rename from internal/command/e2etest/testdata/empty/.exists rename to command/e2etest/testdata/empty/.exists diff --git a/internal/command/e2etest/testdata/full-workflow-null/main.tf b/command/e2etest/testdata/full-workflow-null/main.tf similarity index 100% rename from internal/command/e2etest/testdata/full-workflow-null/main.tf rename to command/e2etest/testdata/full-workflow-null/main.tf diff --git a/internal/command/e2etest/testdata/local-only-provider/main.tf b/command/e2etest/testdata/local-only-provider/main.tf similarity index 100% rename from internal/command/e2etest/testdata/local-only-provider/main.tf rename to command/e2etest/testdata/local-only-provider/main.tf diff --git a/internal/command/e2etest/testdata/local-only-provider/terraform.d/plugins/example.com/awesomecorp/happycloud/1.2.0/os_arch/terraform-provider-happycloud_v1.2.0 b/command/e2etest/testdata/local-only-provider/terraform.d/plugins/example.com/awesomecorp/happycloud/1.2.0/os_arch/terraform-provider-happycloud_v1.2.0 similarity index 100% rename from internal/command/e2etest/testdata/local-only-provider/terraform.d/plugins/example.com/awesomecorp/happycloud/1.2.0/os_arch/terraform-provider-happycloud_v1.2.0 rename to command/e2etest/testdata/local-only-provider/terraform.d/plugins/example.com/awesomecorp/happycloud/1.2.0/os_arch/terraform-provider-happycloud_v1.2.0 diff --git a/internal/command/e2etest/testdata/module-archive/main.tf b/command/e2etest/testdata/module-archive/main.tf similarity index 100% rename from internal/command/e2etest/testdata/module-archive/main.tf rename to command/e2etest/testdata/module-archive/main.tf diff --git a/internal/command/e2etest/testdata/plugin-cache/.terraform.lock.hcl b/command/e2etest/testdata/plugin-cache/.terraform.lock.hcl similarity index 100% rename from internal/command/e2etest/testdata/plugin-cache/.terraform.lock.hcl rename to command/e2etest/testdata/plugin-cache/.terraform.lock.hcl diff --git a/internal/command/e2etest/testdata/plugin-cache/cache/registry.terraform.io/hashicorp/template/2.1.0/os_arch/terraform-provider-template_v2.1.0_x4 b/command/e2etest/testdata/plugin-cache/cache/registry.terraform.io/hashicorp/template/2.1.0/os_arch/terraform-provider-template_v2.1.0_x4 similarity index 100% rename from internal/command/e2etest/testdata/plugin-cache/cache/registry.terraform.io/hashicorp/template/2.1.0/os_arch/terraform-provider-template_v2.1.0_x4 rename to command/e2etest/testdata/plugin-cache/cache/registry.terraform.io/hashicorp/template/2.1.0/os_arch/terraform-provider-template_v2.1.0_x4 diff --git a/internal/command/e2etest/testdata/plugin-cache/main.tf b/command/e2etest/testdata/plugin-cache/main.tf similarity index 100% rename from internal/command/e2etest/testdata/plugin-cache/main.tf rename to command/e2etest/testdata/plugin-cache/main.tf diff --git a/internal/command/e2etest/testdata/provider-dev-override/pkgdir/.exists b/command/e2etest/testdata/provider-dev-override/pkgdir/.exists similarity index 100% rename from internal/command/e2etest/testdata/provider-dev-override/pkgdir/.exists rename to command/e2etest/testdata/provider-dev-override/pkgdir/.exists diff --git a/internal/command/e2etest/testdata/provider-dev-override/provider-dev-override.tf b/command/e2etest/testdata/provider-dev-override/provider-dev-override.tf similarity index 100% rename from internal/command/e2etest/testdata/provider-dev-override/provider-dev-override.tf rename to command/e2etest/testdata/provider-dev-override/provider-dev-override.tf diff --git a/internal/command/e2etest/testdata/provider-not-found-non-default/main.tf b/command/e2etest/testdata/provider-not-found-non-default/main.tf similarity index 100% rename from internal/command/e2etest/testdata/provider-not-found-non-default/main.tf rename to command/e2etest/testdata/provider-not-found-non-default/main.tf diff --git a/internal/command/e2etest/testdata/provider-not-found/main.tf b/command/e2etest/testdata/provider-not-found/main.tf similarity index 100% rename from internal/command/e2etest/testdata/provider-not-found/main.tf rename to command/e2etest/testdata/provider-not-found/main.tf diff --git a/internal/command/e2etest/testdata/provider-plugin/main.tf b/command/e2etest/testdata/provider-plugin/main.tf similarity index 100% rename from internal/command/e2etest/testdata/provider-plugin/main.tf rename to command/e2etest/testdata/provider-plugin/main.tf diff --git a/internal/command/e2etest/testdata/provider-tampering-base/provider-tampering-base.tf b/command/e2etest/testdata/provider-tampering-base/provider-tampering-base.tf similarity index 100% rename from internal/command/e2etest/testdata/provider-tampering-base/provider-tampering-base.tf rename to command/e2etest/testdata/provider-tampering-base/provider-tampering-base.tf diff --git a/internal/command/e2etest/testdata/provider-warnings/main.tf b/command/e2etest/testdata/provider-warnings/main.tf similarity index 100% rename from internal/command/e2etest/testdata/provider-warnings/main.tf rename to command/e2etest/testdata/provider-warnings/main.tf diff --git a/internal/command/e2etest/testdata/provisioner-plugin/main.tf b/command/e2etest/testdata/provisioner-plugin/main.tf similarity index 100% rename from internal/command/e2etest/testdata/provisioner-plugin/main.tf rename to command/e2etest/testdata/provisioner-plugin/main.tf diff --git a/internal/command/e2etest/testdata/provisioner/main.tf b/command/e2etest/testdata/provisioner/main.tf similarity index 100% rename from internal/command/e2etest/testdata/provisioner/main.tf rename to command/e2etest/testdata/provisioner/main.tf diff --git a/internal/command/e2etest/testdata/template-provider/main.tf b/command/e2etest/testdata/template-provider/main.tf similarity index 100% rename from internal/command/e2etest/testdata/template-provider/main.tf rename to command/e2etest/testdata/template-provider/main.tf diff --git a/internal/command/e2etest/testdata/terraform-managed-data/main.tf b/command/e2etest/testdata/terraform-managed-data/main.tf similarity index 100% rename from internal/command/e2etest/testdata/terraform-managed-data/main.tf rename to command/e2etest/testdata/terraform-managed-data/main.tf diff --git a/internal/command/e2etest/testdata/terraform-provider/main.tf b/command/e2etest/testdata/terraform-provider/main.tf similarity index 100% rename from internal/command/e2etest/testdata/terraform-provider/main.tf rename to command/e2etest/testdata/terraform-provider/main.tf diff --git a/internal/command/e2etest/testdata/terraform-provider/test.tfstate b/command/e2etest/testdata/terraform-provider/test.tfstate similarity index 100% rename from internal/command/e2etest/testdata/terraform-provider/test.tfstate rename to command/e2etest/testdata/terraform-provider/test.tfstate diff --git a/internal/command/e2etest/testdata/terraform-providers-mirror-with-lock-file/.terraform.lock.hcl b/command/e2etest/testdata/terraform-providers-mirror-with-lock-file/.terraform.lock.hcl similarity index 100% rename from internal/command/e2etest/testdata/terraform-providers-mirror-with-lock-file/.terraform.lock.hcl rename to command/e2etest/testdata/terraform-providers-mirror-with-lock-file/.terraform.lock.hcl diff --git a/internal/command/e2etest/testdata/terraform-providers-mirror-with-lock-file/terraform-providers-mirror.tf b/command/e2etest/testdata/terraform-providers-mirror-with-lock-file/terraform-providers-mirror.tf similarity index 100% rename from internal/command/e2etest/testdata/terraform-providers-mirror-with-lock-file/terraform-providers-mirror.tf rename to command/e2etest/testdata/terraform-providers-mirror-with-lock-file/terraform-providers-mirror.tf diff --git a/internal/command/e2etest/testdata/terraform-providers-mirror/terraform-providers-mirror.tf b/command/e2etest/testdata/terraform-providers-mirror/terraform-providers-mirror.tf similarity index 100% rename from internal/command/e2etest/testdata/terraform-providers-mirror/terraform-providers-mirror.tf rename to command/e2etest/testdata/terraform-providers-mirror/terraform-providers-mirror.tf diff --git a/internal/command/e2etest/testdata/test-provider/main.tf b/command/e2etest/testdata/test-provider/main.tf similarity index 100% rename from internal/command/e2etest/testdata/test-provider/main.tf rename to command/e2etest/testdata/test-provider/main.tf diff --git a/internal/command/e2etest/testdata/vendored-provider/main.tf b/command/e2etest/testdata/vendored-provider/main.tf similarity index 100% rename from internal/command/e2etest/testdata/vendored-provider/main.tf rename to command/e2etest/testdata/vendored-provider/main.tf diff --git a/internal/command/e2etest/testdata/vendored-provider/terraform.d/plugins/registry.terraform.io/hashicorp/null/1.0.0+local/os_arch/terraform-provider-null_v1.0.0 b/command/e2etest/testdata/vendored-provider/terraform.d/plugins/registry.terraform.io/hashicorp/null/1.0.0+local/os_arch/terraform-provider-null_v1.0.0 similarity index 100% rename from internal/command/e2etest/testdata/vendored-provider/terraform.d/plugins/registry.terraform.io/hashicorp/null/1.0.0+local/os_arch/terraform-provider-null_v1.0.0 rename to command/e2etest/testdata/vendored-provider/terraform.d/plugins/registry.terraform.io/hashicorp/null/1.0.0+local/os_arch/terraform-provider-null_v1.0.0 diff --git a/internal/command/e2etest/unmanaged_test.go b/command/e2etest/unmanaged_test.go similarity index 94% rename from internal/command/e2etest/unmanaged_test.go rename to command/e2etest/unmanaged_test.go index e67e758a3308..1c1f69c33807 100644 --- a/internal/command/e2etest/unmanaged_test.go +++ b/command/e2etest/unmanaged_test.go @@ -11,14 +11,14 @@ import ( "github.com/hashicorp/go-hclog" "github.com/hashicorp/go-plugin" - "github.com/hashicorp/terraform/internal/e2e" - "github.com/hashicorp/terraform/internal/grpcwrap" - tfplugin5 "github.com/hashicorp/terraform/internal/plugin" - tfplugin "github.com/hashicorp/terraform/internal/plugin6" - simple5 "github.com/hashicorp/terraform/internal/provider-simple" - simple "github.com/hashicorp/terraform/internal/provider-simple-v6" - proto5 "github.com/hashicorp/terraform/internal/tfplugin5" - proto "github.com/hashicorp/terraform/internal/tfplugin6" + "github.com/hashicorp/terraform/e2e" + "github.com/hashicorp/terraform/grpcwrap" + tfplugin5 "github.com/hashicorp/terraform/plugin" + tfplugin "github.com/hashicorp/terraform/plugin6" + simple5 "github.com/hashicorp/terraform/provider-simple" + simple "github.com/hashicorp/terraform/provider-simple-v6" + proto5 "github.com/hashicorp/terraform/tfplugin5" + proto "github.com/hashicorp/terraform/tfplugin6" ) // The tests in this file are for the "unmanaged provider workflow", which diff --git a/internal/command/e2etest/version_test.go b/command/e2etest/version_test.go similarity index 98% rename from internal/command/e2etest/version_test.go rename to command/e2etest/version_test.go index 90c716aff4ce..e518feb37763 100644 --- a/internal/command/e2etest/version_test.go +++ b/command/e2etest/version_test.go @@ -6,7 +6,7 @@ import ( "strings" "testing" - "github.com/hashicorp/terraform/internal/e2e" + "github.com/hashicorp/terraform/e2e" "github.com/hashicorp/terraform/version" ) diff --git a/internal/command/flag_kv.go b/command/flag_kv.go similarity index 100% rename from internal/command/flag_kv.go rename to command/flag_kv.go diff --git a/internal/command/flag_kv_test.go b/command/flag_kv_test.go similarity index 100% rename from internal/command/flag_kv_test.go rename to command/flag_kv_test.go diff --git a/internal/command/fmt.go b/command/fmt.go similarity index 99% rename from internal/command/fmt.go rename to command/fmt.go index 64d12e796ff1..3f4d665ccd4e 100644 --- a/internal/command/fmt.go +++ b/command/fmt.go @@ -16,8 +16,8 @@ import ( "github.com/hashicorp/hcl/v2/hclwrite" "github.com/mitchellh/cli" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/tfdiags" ) const ( diff --git a/internal/command/fmt_test.go b/command/fmt_test.go similarity index 100% rename from internal/command/fmt_test.go rename to command/fmt_test.go diff --git a/internal/command/format/diagnostic.go b/command/format/diagnostic.go similarity index 98% rename from internal/command/format/diagnostic.go rename to command/format/diagnostic.go index 780592a08c51..c979219417fb 100644 --- a/internal/command/format/diagnostic.go +++ b/command/format/diagnostic.go @@ -7,8 +7,8 @@ import ( "sort" "strings" - viewsjson "github.com/hashicorp/terraform/internal/command/views/json" - "github.com/hashicorp/terraform/internal/tfdiags" + viewsjson "github.com/hashicorp/terraform/command/views/json" + "github.com/hashicorp/terraform/tfdiags" "github.com/mitchellh/colorstring" wordwrap "github.com/mitchellh/go-wordwrap" diff --git a/internal/command/format/diagnostic_test.go b/command/format/diagnostic_test.go similarity index 99% rename from internal/command/format/diagnostic_test.go rename to command/format/diagnostic_test.go index 95f2ed6aa1ba..5c270423536f 100644 --- a/internal/command/format/diagnostic_test.go +++ b/command/format/diagnostic_test.go @@ -12,10 +12,10 @@ import ( "github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty/function" - viewsjson "github.com/hashicorp/terraform/internal/command/views/json" - "github.com/hashicorp/terraform/internal/lang/marks" + viewsjson "github.com/hashicorp/terraform/command/views/json" + "github.com/hashicorp/terraform/lang/marks" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" ) func TestDiagnostic(t *testing.T) { diff --git a/internal/command/format/diff.go b/command/format/diff.go similarity index 99% rename from internal/command/format/diff.go rename to command/format/diff.go index ed30e3214aff..bfa4c5d130af 100644 --- a/internal/command/format/diff.go +++ b/command/format/diff.go @@ -13,12 +13,12 @@ import ( "github.com/zclconf/go-cty/cty" ctyjson "github.com/zclconf/go-cty/cty/json" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/lang/marks" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/plans/objchange" - "github.com/hashicorp/terraform/internal/states" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/lang/marks" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/plans/objchange" + "github.com/hashicorp/terraform/states" ) // DiffLanguage controls the description of the resource change reasons. diff --git a/internal/command/format/diff_test.go b/command/format/diff_test.go similarity index 99% rename from internal/command/format/diff_test.go rename to command/format/diff_test.go index 5ab9502c37b1..f9e8cc93e503 100644 --- a/internal/command/format/diff_test.go +++ b/command/format/diff_test.go @@ -5,11 +5,11 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/lang/marks" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/lang/marks" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/states" "github.com/mitchellh/colorstring" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/command/format/difflanguage_string.go b/command/format/difflanguage_string.go similarity index 100% rename from internal/command/format/difflanguage_string.go rename to command/format/difflanguage_string.go diff --git a/internal/command/format/format.go b/command/format/format.go similarity index 100% rename from internal/command/format/format.go rename to command/format/format.go diff --git a/internal/command/format/object_id.go b/command/format/object_id.go similarity index 98% rename from internal/command/format/object_id.go rename to command/format/object_id.go index 75b427b8d465..7d5cb5287037 100644 --- a/internal/command/format/object_id.go +++ b/command/format/object_id.go @@ -1,7 +1,7 @@ package format import ( - "github.com/hashicorp/terraform/internal/lang/marks" + "github.com/hashicorp/terraform/lang/marks" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/command/format/object_id_test.go b/command/format/object_id_test.go similarity index 98% rename from internal/command/format/object_id_test.go rename to command/format/object_id_test.go index 2f13e1366caa..ba85784f1925 100644 --- a/internal/command/format/object_id_test.go +++ b/command/format/object_id_test.go @@ -4,7 +4,7 @@ import ( "fmt" "testing" - "github.com/hashicorp/terraform/internal/lang/marks" + "github.com/hashicorp/terraform/lang/marks" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/command/format/state.go b/command/format/state.go similarity index 95% rename from internal/command/format/state.go rename to command/format/state.go index d0db1cc3dd02..9fcb41f1c1e9 100644 --- a/internal/command/format/state.go +++ b/command/format/state.go @@ -8,11 +8,11 @@ import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/terraform" "github.com/mitchellh/colorstring" ) diff --git a/internal/command/format/state_test.go b/command/format/state_test.go similarity index 97% rename from internal/command/format/state_test.go rename to command/format/state_test.go index d83c6eaf9727..fb9da80fb0fd 100644 --- a/internal/command/format/state_test.go +++ b/command/format/state_test.go @@ -4,11 +4,11 @@ import ( "fmt" "testing" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/terraform" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/command/format/trivia.go b/command/format/trivia.go similarity index 100% rename from internal/command/format/trivia.go rename to command/format/trivia.go diff --git a/internal/command/get.go b/command/get.go similarity index 97% rename from internal/command/get.go rename to command/get.go index 0f541c3b1e89..c191f70f963a 100644 --- a/internal/command/get.go +++ b/command/get.go @@ -4,7 +4,7 @@ import ( "fmt" "strings" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" ) // GetCommand is a Command implementation that takes a Terraform diff --git a/internal/command/get_test.go b/command/get_test.go similarity index 100% rename from internal/command/get_test.go rename to command/get_test.go diff --git a/internal/command/graph.go b/command/graph.go similarity index 94% rename from internal/command/graph.go rename to command/graph.go index c1c225beb85b..72784d42a20b 100644 --- a/internal/command/graph.go +++ b/command/graph.go @@ -4,13 +4,13 @@ import ( "fmt" "strings" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/dag" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/plans/planfile" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/dag" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/plans/planfile" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" ) // GraphCommand is a Command implementation that takes a Terraform diff --git a/internal/command/graph_test.go b/command/graph_test.go similarity index 96% rename from internal/command/graph_test.go rename to command/graph_test.go index f58f7103e978..fc21fc611f28 100644 --- a/internal/command/graph_test.go +++ b/command/graph_test.go @@ -8,9 +8,9 @@ import ( "github.com/mitchellh/cli" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/states" ) func TestGraph(t *testing.T) { diff --git a/internal/command/helper.go b/command/helper.go similarity index 87% rename from internal/command/helper.go rename to command/helper.go index acb6c26af0df..1c91d4b1be95 100644 --- a/internal/command/helper.go +++ b/command/helper.go @@ -1,8 +1,8 @@ package command import ( - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/cloud" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/cloud" ) const failedToLoadSchemasMessage = ` diff --git a/internal/command/hook_module_install.go b/command/hook_module_install.go similarity index 94% rename from internal/command/hook_module_install.go rename to command/hook_module_install.go index 4afa7072c30d..d1fa27510b2f 100644 --- a/internal/command/hook_module_install.go +++ b/command/hook_module_install.go @@ -4,7 +4,7 @@ import ( "fmt" version "github.com/hashicorp/go-version" - "github.com/hashicorp/terraform/internal/initwd" + "github.com/hashicorp/terraform/initwd" "github.com/mitchellh/cli" ) diff --git a/internal/command/import.go b/command/import.go similarity index 96% rename from internal/command/import.go rename to command/import.go index 5042cc82e7d6..b79f4cb7b32c 100644 --- a/internal/command/import.go +++ b/command/import.go @@ -10,13 +10,13 @@ import ( "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" ) // ImportCommand is a cli.Command implementation that imports resources diff --git a/internal/command/import_test.go b/command/import_test.go similarity index 99% rename from internal/command/import_test.go rename to command/import_test.go index 6f1ad71b0ca1..3397e82faf84 100644 --- a/internal/command/import_test.go +++ b/command/import_test.go @@ -11,10 +11,10 @@ import ( "github.com/mitchellh/cli" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/copy" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/copy" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/tfdiags" ) func TestImport(t *testing.T) { diff --git a/internal/command/init.go b/command/init.go similarity index 98% rename from internal/command/init.go rename to command/init.go index 2e6d13d9dacf..54eef83aca9d 100644 --- a/internal/command/init.go +++ b/command/init.go @@ -13,18 +13,18 @@ import ( "github.com/posener/complete" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/backend" - backendInit "github.com/hashicorp/terraform/internal/backend/init" - "github.com/hashicorp/terraform/internal/cloud" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/getproviders" - "github.com/hashicorp/terraform/internal/providercache" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/backend" + backendInit "github.com/hashicorp/terraform/backend/init" + "github.com/hashicorp/terraform/cloud" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/getproviders" + "github.com/hashicorp/terraform/providercache" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" tfversion "github.com/hashicorp/terraform/version" ) diff --git a/internal/command/init_test.go b/command/init_test.go similarity index 99% rename from internal/command/init_test.go rename to command/init_test.go index e81db3e205b8..0cbc4de33731 100644 --- a/internal/command/init_test.go +++ b/command/init_test.go @@ -19,15 +19,15 @@ import ( "github.com/hashicorp/go-version" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/depsfile" - "github.com/hashicorp/terraform/internal/getproviders" - "github.com/hashicorp/terraform/internal/providercache" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/statefile" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/depsfile" + "github.com/hashicorp/terraform/getproviders" + "github.com/hashicorp/terraform/providercache" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/statefile" + "github.com/hashicorp/terraform/states/statemgr" ) func TestInit_empty(t *testing.T) { diff --git a/internal/command/jsonchecks/checks.go b/command/jsonchecks/checks.go similarity index 98% rename from internal/command/jsonchecks/checks.go rename to command/jsonchecks/checks.go index 892dcba32530..f82141876229 100644 --- a/internal/command/jsonchecks/checks.go +++ b/command/jsonchecks/checks.go @@ -5,7 +5,7 @@ import ( "fmt" "sort" - "github.com/hashicorp/terraform/internal/states" + "github.com/hashicorp/terraform/states" ) // MarshalCheckStates is the main entry-point for this package, which takes diff --git a/internal/command/jsonchecks/checks_test.go b/command/jsonchecks/checks_test.go similarity index 97% rename from internal/command/jsonchecks/checks_test.go rename to command/jsonchecks/checks_test.go index 6e0f52da4faa..336c2eee9274 100644 --- a/internal/command/jsonchecks/checks_test.go +++ b/command/jsonchecks/checks_test.go @@ -5,9 +5,9 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/checks" - "github.com/hashicorp/terraform/internal/states" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/checks" + "github.com/hashicorp/terraform/states" ) func TestMarshalCheckStates(t *testing.T) { diff --git a/internal/command/jsonchecks/doc.go b/command/jsonchecks/doc.go similarity index 100% rename from internal/command/jsonchecks/doc.go rename to command/jsonchecks/doc.go diff --git a/internal/command/jsonchecks/objects.go b/command/jsonchecks/objects.go similarity index 97% rename from internal/command/jsonchecks/objects.go rename to command/jsonchecks/objects.go index d7a5014fee13..3135ca1c1a3d 100644 --- a/internal/command/jsonchecks/objects.go +++ b/command/jsonchecks/objects.go @@ -3,7 +3,7 @@ package jsonchecks import ( "fmt" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) type staticObjectAddr map[string]interface{} diff --git a/internal/command/jsonchecks/status.go b/command/jsonchecks/status.go similarity index 91% rename from internal/command/jsonchecks/status.go rename to command/jsonchecks/status.go index f55194aeb039..55bb9f6019e7 100644 --- a/internal/command/jsonchecks/status.go +++ b/command/jsonchecks/status.go @@ -3,7 +3,7 @@ package jsonchecks import ( "fmt" - "github.com/hashicorp/terraform/internal/checks" + "github.com/hashicorp/terraform/checks" ) type checkStatus []byte diff --git a/internal/command/jsonconfig/config.go b/command/jsonconfig/config.go similarity index 98% rename from internal/command/jsonconfig/config.go rename to command/jsonconfig/config.go index f744c91086f8..7bd91bba77c0 100644 --- a/internal/command/jsonconfig/config.go +++ b/command/jsonconfig/config.go @@ -8,11 +8,11 @@ import ( "github.com/zclconf/go-cty/cty" ctyjson "github.com/zclconf/go-cty/cty/json" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/getproviders" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/getproviders" + "github.com/hashicorp/terraform/terraform" ) // Config represents the complete configuration source diff --git a/internal/command/jsonconfig/config_test.go b/command/jsonconfig/config_test.go similarity index 100% rename from internal/command/jsonconfig/config_test.go rename to command/jsonconfig/config_test.go diff --git a/internal/command/jsonconfig/doc.go b/command/jsonconfig/doc.go similarity index 100% rename from internal/command/jsonconfig/doc.go rename to command/jsonconfig/doc.go diff --git a/internal/command/jsonconfig/expression.go b/command/jsonconfig/expression.go similarity index 96% rename from internal/command/jsonconfig/expression.go rename to command/jsonconfig/expression.go index fa443fc3ea50..98c499541560 100644 --- a/internal/command/jsonconfig/expression.go +++ b/command/jsonconfig/expression.go @@ -7,10 +7,10 @@ import ( "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hcldec" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/lang" - "github.com/hashicorp/terraform/internal/lang/blocktoattr" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/lang" + "github.com/hashicorp/terraform/lang/blocktoattr" "github.com/zclconf/go-cty/cty" ctyjson "github.com/zclconf/go-cty/cty/json" ) diff --git a/internal/command/jsonconfig/expression_test.go b/command/jsonconfig/expression_test.go similarity index 97% rename from internal/command/jsonconfig/expression_test.go rename to command/jsonconfig/expression_test.go index 58af11dda53e..c81447e467fc 100644 --- a/internal/command/jsonconfig/expression_test.go +++ b/command/jsonconfig/expression_test.go @@ -10,7 +10,7 @@ import ( "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclsyntax" "github.com/hashicorp/hcl/v2/hcltest" - "github.com/hashicorp/terraform/internal/configs/configschema" + "github.com/hashicorp/terraform/configs/configschema" ) func TestMarshalExpressions(t *testing.T) { diff --git a/internal/command/jsonformat/README.md b/command/jsonformat/README.md similarity index 100% rename from internal/command/jsonformat/README.md rename to command/jsonformat/README.md diff --git a/internal/command/jsonformat/collections/action.go b/command/jsonformat/collections/action.go similarity index 85% rename from internal/command/jsonformat/collections/action.go rename to command/jsonformat/collections/action.go index 97f7d7d7ab43..edacf6c110ae 100644 --- a/internal/command/jsonformat/collections/action.go +++ b/command/jsonformat/collections/action.go @@ -1,6 +1,6 @@ package collections -import "github.com/hashicorp/terraform/internal/plans" +import "github.com/hashicorp/terraform/plans" // CompareActions will compare current and next, and return plans.Update if they // are different, and current if they are the same. diff --git a/internal/command/jsonformat/collections/map.go b/command/jsonformat/collections/map.go similarity index 82% rename from internal/command/jsonformat/collections/map.go rename to command/jsonformat/collections/map.go index ecc8ece92abe..e6603dc41022 100644 --- a/internal/command/jsonformat/collections/map.go +++ b/command/jsonformat/collections/map.go @@ -1,8 +1,8 @@ package collections import ( - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/command/jsonformat/computed" + "github.com/hashicorp/terraform/plans" ) type ProcessKey func(key string) computed.Diff diff --git a/internal/command/jsonformat/collections/slice.go b/command/jsonformat/collections/slice.go similarity index 92% rename from internal/command/jsonformat/collections/slice.go rename to command/jsonformat/collections/slice.go index b584dbef7f44..1e87baa80fc2 100644 --- a/internal/command/jsonformat/collections/slice.go +++ b/command/jsonformat/collections/slice.go @@ -3,10 +3,10 @@ package collections import ( "reflect" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" + "github.com/hashicorp/terraform/command/jsonformat/computed" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/plans/objchange" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/plans/objchange" ) type TransformIndices func(before, after int) computed.Diff diff --git a/internal/command/jsonformat/computed/diff.go b/command/jsonformat/computed/diff.go similarity index 98% rename from internal/command/jsonformat/computed/diff.go rename to command/jsonformat/computed/diff.go index 6f6980c9f449..e1878317c375 100644 --- a/internal/command/jsonformat/computed/diff.go +++ b/command/jsonformat/computed/diff.go @@ -3,7 +3,7 @@ package computed import ( "github.com/mitchellh/colorstring" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/plans" ) // Diff captures the computed diff for a single block, element or attribute. diff --git a/internal/command/jsonformat/computed/doc.go b/command/jsonformat/computed/doc.go similarity index 100% rename from internal/command/jsonformat/computed/doc.go rename to command/jsonformat/computed/doc.go diff --git a/internal/command/jsonformat/computed/renderers/block.go b/command/jsonformat/computed/renderers/block.go similarity index 98% rename from internal/command/jsonformat/computed/renderers/block.go rename to command/jsonformat/computed/renderers/block.go index 17f2dbf1dca1..cdcc2cf5b794 100644 --- a/internal/command/jsonformat/computed/renderers/block.go +++ b/command/jsonformat/computed/renderers/block.go @@ -5,9 +5,9 @@ import ( "fmt" "sort" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" + "github.com/hashicorp/terraform/command/jsonformat/computed" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/plans" ) var ( diff --git a/internal/command/jsonformat/computed/renderers/blocks.go b/command/jsonformat/computed/renderers/blocks.go similarity index 97% rename from internal/command/jsonformat/computed/renderers/blocks.go rename to command/jsonformat/computed/renderers/blocks.go index 62f2f7912943..fda59db328c2 100644 --- a/internal/command/jsonformat/computed/renderers/blocks.go +++ b/command/jsonformat/computed/renderers/blocks.go @@ -3,7 +3,7 @@ package renderers import ( "sort" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" + "github.com/hashicorp/terraform/command/jsonformat/computed" ) // Blocks is a helper struct for collating the different kinds of blocks in a diff --git a/internal/command/jsonformat/computed/renderers/json.go b/command/jsonformat/computed/renderers/json.go similarity index 88% rename from internal/command/jsonformat/computed/renderers/json.go rename to command/jsonformat/computed/renderers/json.go index 61ab7d5a4f99..2d3c7cc88e8d 100644 --- a/internal/command/jsonformat/computed/renderers/json.go +++ b/command/jsonformat/computed/renderers/json.go @@ -3,9 +3,9 @@ package renderers import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" - "github.com/hashicorp/terraform/internal/command/jsonformat/jsondiff" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/command/jsonformat/computed" + "github.com/hashicorp/terraform/command/jsonformat/jsondiff" + "github.com/hashicorp/terraform/plans" ) // RendererJsonOpts creates a jsondiff.JsonOpts object that returns the correct diff --git a/internal/command/jsonformat/computed/renderers/list.go b/command/jsonformat/computed/renderers/list.go similarity index 97% rename from internal/command/jsonformat/computed/renderers/list.go rename to command/jsonformat/computed/renderers/list.go index 0b79ce026bf7..8ab626a0024d 100644 --- a/internal/command/jsonformat/computed/renderers/list.go +++ b/command/jsonformat/computed/renderers/list.go @@ -4,8 +4,8 @@ import ( "bytes" "fmt" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/command/jsonformat/computed" + "github.com/hashicorp/terraform/plans" ) var _ computed.DiffRenderer = (*listRenderer)(nil) diff --git a/internal/command/jsonformat/computed/renderers/map.go b/command/jsonformat/computed/renderers/map.go similarity index 96% rename from internal/command/jsonformat/computed/renderers/map.go rename to command/jsonformat/computed/renderers/map.go index 10ad997464d5..6aa4d68f21c6 100644 --- a/internal/command/jsonformat/computed/renderers/map.go +++ b/command/jsonformat/computed/renderers/map.go @@ -5,9 +5,9 @@ import ( "fmt" "sort" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" + "github.com/hashicorp/terraform/command/jsonformat/computed" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/plans" ) var _ computed.DiffRenderer = (*mapRenderer)(nil) diff --git a/internal/command/jsonformat/computed/renderers/object.go b/command/jsonformat/computed/renderers/object.go similarity index 96% rename from internal/command/jsonformat/computed/renderers/object.go rename to command/jsonformat/computed/renderers/object.go index 7cf9710fb550..66a8a16b464b 100644 --- a/internal/command/jsonformat/computed/renderers/object.go +++ b/command/jsonformat/computed/renderers/object.go @@ -5,8 +5,8 @@ import ( "fmt" "sort" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/command/jsonformat/computed" + "github.com/hashicorp/terraform/plans" ) var _ computed.DiffRenderer = (*objectRenderer)(nil) diff --git a/internal/command/jsonformat/computed/renderers/primitive.go b/command/jsonformat/computed/renderers/primitive.go similarity index 96% rename from internal/command/jsonformat/computed/renderers/primitive.go rename to command/jsonformat/computed/renderers/primitive.go index efc273692e91..06c53baf09bb 100644 --- a/internal/command/jsonformat/computed/renderers/primitive.go +++ b/command/jsonformat/computed/renderers/primitive.go @@ -7,11 +7,11 @@ import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/command/jsonformat/collections" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" - "github.com/hashicorp/terraform/internal/command/jsonformat/structured" - "github.com/hashicorp/terraform/internal/command/jsonformat/structured/attribute_path" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/command/jsonformat/collections" + "github.com/hashicorp/terraform/command/jsonformat/computed" + "github.com/hashicorp/terraform/command/jsonformat/structured" + "github.com/hashicorp/terraform/command/jsonformat/structured/attribute_path" + "github.com/hashicorp/terraform/plans" ) var _ computed.DiffRenderer = (*primitiveRenderer)(nil) diff --git a/internal/command/jsonformat/computed/renderers/renderer_test.go b/command/jsonformat/computed/renderers/renderer_test.go similarity index 99% rename from internal/command/jsonformat/computed/renderers/renderer_test.go rename to command/jsonformat/computed/renderers/renderer_test.go index ae49a0974f38..da2957cc248d 100644 --- a/internal/command/jsonformat/computed/renderers/renderer_test.go +++ b/command/jsonformat/computed/renderers/renderer_test.go @@ -4,13 +4,13 @@ import ( "strings" "testing" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" + "github.com/hashicorp/terraform/command/jsonformat/computed" "github.com/google/go-cmp/cmp" "github.com/mitchellh/colorstring" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/plans" ) func TestRenderers_Human(t *testing.T) { diff --git a/internal/command/jsonformat/computed/renderers/sensitive.go b/command/jsonformat/computed/renderers/sensitive.go similarity index 93% rename from internal/command/jsonformat/computed/renderers/sensitive.go rename to command/jsonformat/computed/renderers/sensitive.go index cb0b9e7f1dc0..8034274e2cd9 100644 --- a/internal/command/jsonformat/computed/renderers/sensitive.go +++ b/command/jsonformat/computed/renderers/sensitive.go @@ -3,8 +3,8 @@ package renderers import ( "fmt" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/command/jsonformat/computed" + "github.com/hashicorp/terraform/plans" ) var _ computed.DiffRenderer = (*sensitiveRenderer)(nil) diff --git a/internal/command/jsonformat/computed/renderers/sensitive_block.go b/command/jsonformat/computed/renderers/sensitive_block.go similarity index 93% rename from internal/command/jsonformat/computed/renderers/sensitive_block.go rename to command/jsonformat/computed/renderers/sensitive_block.go index e5c129862f22..8e3d3f79f470 100644 --- a/internal/command/jsonformat/computed/renderers/sensitive_block.go +++ b/command/jsonformat/computed/renderers/sensitive_block.go @@ -3,8 +3,8 @@ package renderers import ( "fmt" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/command/jsonformat/computed" + "github.com/hashicorp/terraform/plans" ) func SensitiveBlock(diff computed.Diff, beforeSensitive, afterSensitive bool) computed.DiffRenderer { diff --git a/internal/command/jsonformat/computed/renderers/set.go b/command/jsonformat/computed/renderers/set.go similarity index 95% rename from internal/command/jsonformat/computed/renderers/set.go rename to command/jsonformat/computed/renderers/set.go index 8848fbc15ada..1e459f4b2292 100644 --- a/internal/command/jsonformat/computed/renderers/set.go +++ b/command/jsonformat/computed/renderers/set.go @@ -4,8 +4,8 @@ import ( "bytes" "fmt" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/command/jsonformat/computed" + "github.com/hashicorp/terraform/plans" ) var _ computed.DiffRenderer = (*setRenderer)(nil) diff --git a/internal/command/jsonformat/computed/renderers/string.go b/command/jsonformat/computed/renderers/string.go similarity index 92% rename from internal/command/jsonformat/computed/renderers/string.go rename to command/jsonformat/computed/renderers/string.go index 7777a3eb4239..cec5fd9e9c5c 100644 --- a/internal/command/jsonformat/computed/renderers/string.go +++ b/command/jsonformat/computed/renderers/string.go @@ -5,7 +5,7 @@ import ( "fmt" "strings" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" + "github.com/hashicorp/terraform/command/jsonformat/computed" ) type evaluatedString struct { diff --git a/internal/command/jsonformat/computed/renderers/testing.go b/command/jsonformat/computed/renderers/testing.go similarity index 98% rename from internal/command/jsonformat/computed/renderers/testing.go rename to command/jsonformat/computed/renderers/testing.go index 4adbcc2ee7c2..2c791f5971f6 100644 --- a/internal/command/jsonformat/computed/renderers/testing.go +++ b/command/jsonformat/computed/renderers/testing.go @@ -6,8 +6,8 @@ import ( "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/command/jsonformat/computed" + "github.com/hashicorp/terraform/plans" ) type ValidateDiffFunction func(t *testing.T, diff computed.Diff) diff --git a/internal/command/jsonformat/computed/renderers/type_change.go b/command/jsonformat/computed/renderers/type_change.go similarity index 90% rename from internal/command/jsonformat/computed/renderers/type_change.go rename to command/jsonformat/computed/renderers/type_change.go index 7469b51be6ac..d8d823d6f44f 100644 --- a/internal/command/jsonformat/computed/renderers/type_change.go +++ b/command/jsonformat/computed/renderers/type_change.go @@ -3,7 +3,7 @@ package renderers import ( "fmt" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" + "github.com/hashicorp/terraform/command/jsonformat/computed" ) var _ computed.DiffRenderer = (*typeChangeRenderer)(nil) diff --git a/internal/command/jsonformat/computed/renderers/unknown.go b/command/jsonformat/computed/renderers/unknown.go similarity index 86% rename from internal/command/jsonformat/computed/renderers/unknown.go rename to command/jsonformat/computed/renderers/unknown.go index f24b836a032e..51ea7cac7db1 100644 --- a/internal/command/jsonformat/computed/renderers/unknown.go +++ b/command/jsonformat/computed/renderers/unknown.go @@ -3,9 +3,9 @@ package renderers import ( "fmt" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" + "github.com/hashicorp/terraform/command/jsonformat/computed" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/plans" ) var _ computed.DiffRenderer = (*unknownRenderer)(nil) diff --git a/internal/command/jsonformat/computed/renderers/util.go b/command/jsonformat/computed/renderers/util.go similarity index 94% rename from internal/command/jsonformat/computed/renderers/util.go rename to command/jsonformat/computed/renderers/util.go index bb29acccbbc4..5381d3f0b4bf 100644 --- a/internal/command/jsonformat/computed/renderers/util.go +++ b/command/jsonformat/computed/renderers/util.go @@ -4,12 +4,12 @@ import ( "fmt" "strings" - "github.com/hashicorp/terraform/internal/command/format" + "github.com/hashicorp/terraform/command/format" "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/command/jsonformat/computed" + "github.com/hashicorp/terraform/plans" ) // NoWarningsRenderer defines a Warnings function that returns an empty list of diff --git a/internal/command/jsonformat/diff.go b/command/jsonformat/diff.go similarity index 84% rename from internal/command/jsonformat/diff.go rename to command/jsonformat/diff.go index fc8b60009001..007bd98a5599 100644 --- a/internal/command/jsonformat/diff.go +++ b/command/jsonformat/diff.go @@ -1,12 +1,12 @@ package jsonformat import ( - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" - "github.com/hashicorp/terraform/internal/command/jsonformat/differ" - "github.com/hashicorp/terraform/internal/command/jsonformat/structured" - "github.com/hashicorp/terraform/internal/command/jsonformat/structured/attribute_path" - "github.com/hashicorp/terraform/internal/command/jsonplan" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/command/jsonformat/computed" + "github.com/hashicorp/terraform/command/jsonformat/differ" + "github.com/hashicorp/terraform/command/jsonformat/structured" + "github.com/hashicorp/terraform/command/jsonformat/structured/attribute_path" + "github.com/hashicorp/terraform/command/jsonplan" + "github.com/hashicorp/terraform/plans" ) func precomputeDiffs(plan Plan, mode plans.Mode) diffs { diff --git a/internal/command/jsonformat/differ/attribute.go b/command/jsonformat/differ/attribute.go similarity index 93% rename from internal/command/jsonformat/differ/attribute.go rename to command/jsonformat/differ/attribute.go index e1c913ddc769..854699a328cd 100644 --- a/internal/command/jsonformat/differ/attribute.go +++ b/command/jsonformat/differ/attribute.go @@ -1,13 +1,13 @@ package differ import ( - "github.com/hashicorp/terraform/internal/command/jsonformat/structured" + "github.com/hashicorp/terraform/command/jsonformat/structured" "github.com/zclconf/go-cty/cty" ctyjson "github.com/zclconf/go-cty/cty/json" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" + "github.com/hashicorp/terraform/command/jsonformat/computed" - "github.com/hashicorp/terraform/internal/command/jsonprovider" + "github.com/hashicorp/terraform/command/jsonprovider" ) func ComputeDiffForAttribute(change structured.Change, attribute *jsonprovider.Attribute) computed.Diff { diff --git a/internal/command/jsonformat/differ/block.go b/command/jsonformat/differ/block.go similarity index 90% rename from internal/command/jsonformat/differ/block.go rename to command/jsonformat/differ/block.go index 9b2375c76fb7..5aad75d03496 100644 --- a/internal/command/jsonformat/differ/block.go +++ b/command/jsonformat/differ/block.go @@ -1,12 +1,12 @@ package differ import ( - "github.com/hashicorp/terraform/internal/command/jsonformat/collections" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed/renderers" - "github.com/hashicorp/terraform/internal/command/jsonformat/structured" - "github.com/hashicorp/terraform/internal/command/jsonprovider" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/command/jsonformat/collections" + "github.com/hashicorp/terraform/command/jsonformat/computed" + "github.com/hashicorp/terraform/command/jsonformat/computed/renderers" + "github.com/hashicorp/terraform/command/jsonformat/structured" + "github.com/hashicorp/terraform/command/jsonprovider" + "github.com/hashicorp/terraform/plans" ) func ComputeDiffForBlock(change structured.Change, block *jsonprovider.Block) computed.Diff { diff --git a/internal/command/jsonformat/differ/differ.go b/command/jsonformat/differ/differ.go similarity index 70% rename from internal/command/jsonformat/differ/differ.go rename to command/jsonformat/differ/differ.go index 3ca584e8d4ca..e5d7a6b08fe9 100644 --- a/internal/command/jsonformat/differ/differ.go +++ b/command/jsonformat/differ/differ.go @@ -1,8 +1,8 @@ package differ import ( - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" - "github.com/hashicorp/terraform/internal/command/jsonformat/structured" + "github.com/hashicorp/terraform/command/jsonformat/computed" + "github.com/hashicorp/terraform/command/jsonformat/structured" ) // asDiff is a helper function to abstract away some simple and common diff --git a/internal/command/jsonformat/differ/differ_test.go b/command/jsonformat/differ/differ_test.go similarity index 99% rename from internal/command/jsonformat/differ/differ_test.go rename to command/jsonformat/differ/differ_test.go index 817336ef352d..77d9bdd4f5e2 100644 --- a/internal/command/jsonformat/differ/differ_test.go +++ b/command/jsonformat/differ/differ_test.go @@ -8,11 +8,11 @@ import ( "github.com/zclconf/go-cty/cty" ctyjson "github.com/zclconf/go-cty/cty/json" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed/renderers" - "github.com/hashicorp/terraform/internal/command/jsonformat/structured" - "github.com/hashicorp/terraform/internal/command/jsonformat/structured/attribute_path" - "github.com/hashicorp/terraform/internal/command/jsonprovider" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/command/jsonformat/computed/renderers" + "github.com/hashicorp/terraform/command/jsonformat/structured" + "github.com/hashicorp/terraform/command/jsonformat/structured/attribute_path" + "github.com/hashicorp/terraform/command/jsonprovider" + "github.com/hashicorp/terraform/plans" ) type SetDiff struct { diff --git a/internal/command/jsonformat/differ/list.go b/command/jsonformat/differ/list.go similarity index 86% rename from internal/command/jsonformat/differ/list.go rename to command/jsonformat/differ/list.go index 0ce937df46e8..aa8773a2eb26 100644 --- a/internal/command/jsonformat/differ/list.go +++ b/command/jsonformat/differ/list.go @@ -3,13 +3,13 @@ package differ import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/command/jsonformat/collections" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed/renderers" - "github.com/hashicorp/terraform/internal/command/jsonformat/structured" - "github.com/hashicorp/terraform/internal/command/jsonformat/structured/attribute_path" - "github.com/hashicorp/terraform/internal/command/jsonprovider" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/command/jsonformat/collections" + "github.com/hashicorp/terraform/command/jsonformat/computed" + "github.com/hashicorp/terraform/command/jsonformat/computed/renderers" + "github.com/hashicorp/terraform/command/jsonformat/structured" + "github.com/hashicorp/terraform/command/jsonformat/structured/attribute_path" + "github.com/hashicorp/terraform/command/jsonprovider" + "github.com/hashicorp/terraform/plans" ) func computeAttributeDiffAsList(change structured.Change, elementType cty.Type) computed.Diff { diff --git a/internal/command/jsonformat/differ/map.go b/command/jsonformat/differ/map.go similarity index 81% rename from internal/command/jsonformat/differ/map.go rename to command/jsonformat/differ/map.go index e9f09542045e..fd2d5a9c55be 100644 --- a/internal/command/jsonformat/differ/map.go +++ b/command/jsonformat/differ/map.go @@ -3,12 +3,12 @@ package differ import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/command/jsonformat/collections" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed/renderers" - "github.com/hashicorp/terraform/internal/command/jsonformat/structured" - "github.com/hashicorp/terraform/internal/command/jsonprovider" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/command/jsonformat/collections" + "github.com/hashicorp/terraform/command/jsonformat/computed" + "github.com/hashicorp/terraform/command/jsonformat/computed/renderers" + "github.com/hashicorp/terraform/command/jsonformat/structured" + "github.com/hashicorp/terraform/command/jsonprovider" + "github.com/hashicorp/terraform/plans" ) func computeAttributeDiffAsMap(change structured.Change, elementType cty.Type) computed.Diff { diff --git a/internal/command/jsonformat/differ/object.go b/command/jsonformat/differ/object.go similarity index 86% rename from internal/command/jsonformat/differ/object.go rename to command/jsonformat/differ/object.go index 657089af97ab..6b6c77899ff0 100644 --- a/internal/command/jsonformat/differ/object.go +++ b/command/jsonformat/differ/object.go @@ -3,12 +3,12 @@ package differ import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/command/jsonformat/collections" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed/renderers" - "github.com/hashicorp/terraform/internal/command/jsonformat/structured" - "github.com/hashicorp/terraform/internal/command/jsonprovider" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/command/jsonformat/collections" + "github.com/hashicorp/terraform/command/jsonformat/computed" + "github.com/hashicorp/terraform/command/jsonformat/computed/renderers" + "github.com/hashicorp/terraform/command/jsonformat/structured" + "github.com/hashicorp/terraform/command/jsonprovider" + "github.com/hashicorp/terraform/plans" ) func computeAttributeDiffAsObject(change structured.Change, attributes map[string]cty.Type) computed.Diff { diff --git a/internal/command/jsonformat/differ/output.go b/command/jsonformat/differ/output.go similarity index 64% rename from internal/command/jsonformat/differ/output.go rename to command/jsonformat/differ/output.go index 5ab4bf411641..22b1441f0942 100644 --- a/internal/command/jsonformat/differ/output.go +++ b/command/jsonformat/differ/output.go @@ -3,9 +3,9 @@ package differ import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed/renderers" - "github.com/hashicorp/terraform/internal/command/jsonformat/structured" + "github.com/hashicorp/terraform/command/jsonformat/computed" + "github.com/hashicorp/terraform/command/jsonformat/computed/renderers" + "github.com/hashicorp/terraform/command/jsonformat/structured" ) func ComputeDiffForOutput(change structured.Change) computed.Diff { diff --git a/internal/command/jsonformat/differ/primitive.go b/command/jsonformat/differ/primitive.go similarity index 51% rename from internal/command/jsonformat/differ/primitive.go rename to command/jsonformat/differ/primitive.go index a1dcc6ec21cf..0532bb088a78 100644 --- a/internal/command/jsonformat/differ/primitive.go +++ b/command/jsonformat/differ/primitive.go @@ -3,9 +3,9 @@ package differ import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed/renderers" - "github.com/hashicorp/terraform/internal/command/jsonformat/structured" + "github.com/hashicorp/terraform/command/jsonformat/computed" + "github.com/hashicorp/terraform/command/jsonformat/computed/renderers" + "github.com/hashicorp/terraform/command/jsonformat/structured" ) func computeAttributeDiffAsPrimitive(change structured.Change, ctype cty.Type) computed.Diff { diff --git a/internal/command/jsonformat/differ/sensitive.go b/command/jsonformat/differ/sensitive.go similarity index 82% rename from internal/command/jsonformat/differ/sensitive.go rename to command/jsonformat/differ/sensitive.go index 90a7a2886e5f..ab66ea9c9fc9 100644 --- a/internal/command/jsonformat/differ/sensitive.go +++ b/command/jsonformat/differ/sensitive.go @@ -3,11 +3,11 @@ package differ import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed/renderers" - "github.com/hashicorp/terraform/internal/command/jsonformat/structured" - "github.com/hashicorp/terraform/internal/command/jsonprovider" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/command/jsonformat/computed" + "github.com/hashicorp/terraform/command/jsonformat/computed/renderers" + "github.com/hashicorp/terraform/command/jsonformat/structured" + "github.com/hashicorp/terraform/command/jsonprovider" + "github.com/hashicorp/terraform/plans" ) type CreateSensitiveRenderer func(computed.Diff, bool, bool) computed.DiffRenderer diff --git a/internal/command/jsonformat/differ/set.go b/command/jsonformat/differ/set.go similarity index 90% rename from internal/command/jsonformat/differ/set.go rename to command/jsonformat/differ/set.go index 8e0bccbbd4b6..39ea6cbde84f 100644 --- a/internal/command/jsonformat/differ/set.go +++ b/command/jsonformat/differ/set.go @@ -5,13 +5,13 @@ import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/command/jsonformat/collections" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed/renderers" - "github.com/hashicorp/terraform/internal/command/jsonformat/structured" - "github.com/hashicorp/terraform/internal/command/jsonformat/structured/attribute_path" - "github.com/hashicorp/terraform/internal/command/jsonprovider" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/command/jsonformat/collections" + "github.com/hashicorp/terraform/command/jsonformat/computed" + "github.com/hashicorp/terraform/command/jsonformat/computed/renderers" + "github.com/hashicorp/terraform/command/jsonformat/structured" + "github.com/hashicorp/terraform/command/jsonformat/structured/attribute_path" + "github.com/hashicorp/terraform/command/jsonprovider" + "github.com/hashicorp/terraform/plans" ) func computeAttributeDiffAsSet(change structured.Change, elementType cty.Type) computed.Diff { diff --git a/internal/command/jsonformat/differ/tuple.go b/command/jsonformat/differ/tuple.go similarity index 71% rename from internal/command/jsonformat/differ/tuple.go rename to command/jsonformat/differ/tuple.go index f45023b0f67e..57fb7b46b70d 100644 --- a/internal/command/jsonformat/differ/tuple.go +++ b/command/jsonformat/differ/tuple.go @@ -3,10 +3,10 @@ package differ import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/command/jsonformat/collections" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed/renderers" - "github.com/hashicorp/terraform/internal/command/jsonformat/structured" + "github.com/hashicorp/terraform/command/jsonformat/collections" + "github.com/hashicorp/terraform/command/jsonformat/computed" + "github.com/hashicorp/terraform/command/jsonformat/computed/renderers" + "github.com/hashicorp/terraform/command/jsonformat/structured" ) func computeAttributeDiffAsTuple(change structured.Change, elementTypes []cty.Type) computed.Diff { diff --git a/internal/command/jsonformat/differ/types.go b/command/jsonformat/differ/types.go similarity index 100% rename from internal/command/jsonformat/differ/types.go rename to command/jsonformat/differ/types.go diff --git a/internal/command/jsonformat/differ/unknown.go b/command/jsonformat/differ/unknown.go similarity index 86% rename from internal/command/jsonformat/differ/unknown.go rename to command/jsonformat/differ/unknown.go index 2a0bfa5e2152..690b024661b0 100644 --- a/internal/command/jsonformat/differ/unknown.go +++ b/command/jsonformat/differ/unknown.go @@ -3,10 +3,10 @@ package differ import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed/renderers" - "github.com/hashicorp/terraform/internal/command/jsonformat/structured" - "github.com/hashicorp/terraform/internal/command/jsonprovider" + "github.com/hashicorp/terraform/command/jsonformat/computed" + "github.com/hashicorp/terraform/command/jsonformat/computed/renderers" + "github.com/hashicorp/terraform/command/jsonformat/structured" + "github.com/hashicorp/terraform/command/jsonprovider" ) func checkForUnknownType(change structured.Change, ctype cty.Type) (computed.Diff, bool) { diff --git a/internal/command/jsonformat/jsondiff/diff.go b/command/jsonformat/jsondiff/diff.go similarity index 94% rename from internal/command/jsonformat/jsondiff/diff.go rename to command/jsonformat/jsondiff/diff.go index 99bc4137c8ec..0172483e6142 100644 --- a/internal/command/jsonformat/jsondiff/diff.go +++ b/command/jsonformat/jsondiff/diff.go @@ -5,10 +5,10 @@ import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/command/jsonformat/collections" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" - "github.com/hashicorp/terraform/internal/command/jsonformat/structured" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/command/jsonformat/collections" + "github.com/hashicorp/terraform/command/jsonformat/computed" + "github.com/hashicorp/terraform/command/jsonformat/structured" + "github.com/hashicorp/terraform/plans" ) type TransformPrimitiveJson func(before, after interface{}, ctype cty.Type, action plans.Action) computed.Diff diff --git a/internal/command/jsonformat/jsondiff/types.go b/command/jsonformat/jsondiff/types.go similarity index 100% rename from internal/command/jsonformat/jsondiff/types.go rename to command/jsonformat/jsondiff/types.go diff --git a/internal/command/jsonformat/plan.go b/command/jsonformat/plan.go similarity index 97% rename from internal/command/jsonformat/plan.go rename to command/jsonformat/plan.go index 5deaeca54467..e7499f84fc9a 100644 --- a/internal/command/jsonformat/plan.go +++ b/command/jsonformat/plan.go @@ -7,13 +7,13 @@ import ( "sort" "strings" - "github.com/hashicorp/terraform/internal/command/format" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed/renderers" - "github.com/hashicorp/terraform/internal/command/jsonplan" - "github.com/hashicorp/terraform/internal/command/jsonprovider" - "github.com/hashicorp/terraform/internal/command/jsonstate" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/command/format" + "github.com/hashicorp/terraform/command/jsonformat/computed" + "github.com/hashicorp/terraform/command/jsonformat/computed/renderers" + "github.com/hashicorp/terraform/command/jsonplan" + "github.com/hashicorp/terraform/command/jsonprovider" + "github.com/hashicorp/terraform/command/jsonstate" + "github.com/hashicorp/terraform/plans" ) type PlanRendererOpt int diff --git a/internal/command/jsonformat/plan_test.go b/command/jsonformat/plan_test.go similarity index 99% rename from internal/command/jsonformat/plan_test.go rename to command/jsonformat/plan_test.go index 077d29afa073..124aa8b66574 100644 --- a/internal/command/jsonformat/plan_test.go +++ b/command/jsonformat/plan_test.go @@ -9,19 +9,19 @@ import ( "github.com/mitchellh/colorstring" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/command/jsonformat/differ" - "github.com/hashicorp/terraform/internal/command/jsonformat/structured" - "github.com/hashicorp/terraform/internal/command/jsonformat/structured/attribute_path" - "github.com/hashicorp/terraform/internal/command/jsonplan" - "github.com/hashicorp/terraform/internal/command/jsonprovider" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/lang/marks" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/terminal" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/command/jsonformat/differ" + "github.com/hashicorp/terraform/command/jsonformat/structured" + "github.com/hashicorp/terraform/command/jsonformat/structured/attribute_path" + "github.com/hashicorp/terraform/command/jsonplan" + "github.com/hashicorp/terraform/command/jsonprovider" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/lang/marks" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/terminal" + "github.com/hashicorp/terraform/terraform" ) func TestRenderHuman_EmptyPlan(t *testing.T) { diff --git a/internal/command/jsonformat/renderer.go b/command/jsonformat/renderer.go similarity index 89% rename from internal/command/jsonformat/renderer.go rename to command/jsonformat/renderer.go index 676d6cad7d0f..286790cc418f 100644 --- a/internal/command/jsonformat/renderer.go +++ b/command/jsonformat/renderer.go @@ -5,16 +5,16 @@ import ( "github.com/mitchellh/colorstring" - "github.com/hashicorp/terraform/internal/command/format" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" - "github.com/hashicorp/terraform/internal/command/jsonformat/differ" - "github.com/hashicorp/terraform/internal/command/jsonformat/structured" - "github.com/hashicorp/terraform/internal/command/jsonplan" - "github.com/hashicorp/terraform/internal/command/jsonprovider" - "github.com/hashicorp/terraform/internal/command/jsonstate" - viewsjson "github.com/hashicorp/terraform/internal/command/views/json" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/terminal" + "github.com/hashicorp/terraform/command/format" + "github.com/hashicorp/terraform/command/jsonformat/computed" + "github.com/hashicorp/terraform/command/jsonformat/differ" + "github.com/hashicorp/terraform/command/jsonformat/structured" + "github.com/hashicorp/terraform/command/jsonplan" + "github.com/hashicorp/terraform/command/jsonprovider" + "github.com/hashicorp/terraform/command/jsonstate" + viewsjson "github.com/hashicorp/terraform/command/views/json" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/terminal" ctyjson "github.com/zclconf/go-cty/cty/json" ) diff --git a/internal/command/jsonformat/state.go b/command/jsonformat/state.go similarity index 90% rename from internal/command/jsonformat/state.go rename to command/jsonformat/state.go index a86838ff16c8..cd0164e672fc 100644 --- a/internal/command/jsonformat/state.go +++ b/command/jsonformat/state.go @@ -5,11 +5,11 @@ import ( ctyjson "github.com/zclconf/go-cty/cty/json" - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" - "github.com/hashicorp/terraform/internal/command/jsonformat/differ" - "github.com/hashicorp/terraform/internal/command/jsonformat/structured" - "github.com/hashicorp/terraform/internal/command/jsonprovider" - "github.com/hashicorp/terraform/internal/command/jsonstate" + "github.com/hashicorp/terraform/command/jsonformat/computed" + "github.com/hashicorp/terraform/command/jsonformat/differ" + "github.com/hashicorp/terraform/command/jsonformat/structured" + "github.com/hashicorp/terraform/command/jsonprovider" + "github.com/hashicorp/terraform/command/jsonstate" ) type State struct { diff --git a/internal/command/jsonformat/state_test.go b/command/jsonformat/state_test.go similarity index 94% rename from internal/command/jsonformat/state_test.go rename to command/jsonformat/state_test.go index 1728f63a5a0a..d5511de7465f 100644 --- a/internal/command/jsonformat/state_test.go +++ b/command/jsonformat/state_test.go @@ -7,19 +7,19 @@ import ( "github.com/google/go-cmp/cmp" "github.com/mitchellh/colorstring" - "github.com/hashicorp/terraform/internal/command/format" - "github.com/hashicorp/terraform/internal/command/jsonprovider" - "github.com/hashicorp/terraform/internal/command/jsonstate" - "github.com/hashicorp/terraform/internal/states/statefile" - "github.com/hashicorp/terraform/internal/terminal" + "github.com/hashicorp/terraform/command/format" + "github.com/hashicorp/terraform/command/jsonprovider" + "github.com/hashicorp/terraform/command/jsonstate" + "github.com/hashicorp/terraform/states/statefile" + "github.com/hashicorp/terraform/terminal" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/terraform" ) func TestState(t *testing.T) { diff --git a/internal/command/jsonformat/structured/attribute_path/matcher.go b/command/jsonformat/structured/attribute_path/matcher.go similarity index 100% rename from internal/command/jsonformat/structured/attribute_path/matcher.go rename to command/jsonformat/structured/attribute_path/matcher.go diff --git a/internal/command/jsonformat/structured/attribute_path/matcher_test.go b/command/jsonformat/structured/attribute_path/matcher_test.go similarity index 100% rename from internal/command/jsonformat/structured/attribute_path/matcher_test.go rename to command/jsonformat/structured/attribute_path/matcher_test.go diff --git a/internal/command/jsonformat/structured/change.go b/command/jsonformat/structured/change.go similarity index 96% rename from internal/command/jsonformat/structured/change.go rename to command/jsonformat/structured/change.go index 3f06301f928e..ed3ed026af43 100644 --- a/internal/command/jsonformat/structured/change.go +++ b/command/jsonformat/structured/change.go @@ -4,11 +4,11 @@ import ( "encoding/json" "reflect" - "github.com/hashicorp/terraform/internal/command/jsonformat/structured/attribute_path" - "github.com/hashicorp/terraform/internal/command/jsonplan" - "github.com/hashicorp/terraform/internal/command/jsonstate" - viewsjson "github.com/hashicorp/terraform/internal/command/views/json" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/command/jsonformat/structured/attribute_path" + "github.com/hashicorp/terraform/command/jsonplan" + "github.com/hashicorp/terraform/command/jsonstate" + viewsjson "github.com/hashicorp/terraform/command/views/json" + "github.com/hashicorp/terraform/plans" ) // Change contains the unmarshalled generic interface{} types that are output by diff --git a/internal/command/jsonformat/structured/doc.go b/command/jsonformat/structured/doc.go similarity index 100% rename from internal/command/jsonformat/structured/doc.go rename to command/jsonformat/structured/doc.go diff --git a/internal/command/jsonformat/structured/map.go b/command/jsonformat/structured/map.go similarity index 98% rename from internal/command/jsonformat/structured/map.go rename to command/jsonformat/structured/map.go index 0c8268ad6beb..ea1ea24c3a8e 100644 --- a/internal/command/jsonformat/structured/map.go +++ b/command/jsonformat/structured/map.go @@ -1,7 +1,7 @@ package structured import ( - "github.com/hashicorp/terraform/internal/command/jsonformat/structured/attribute_path" + "github.com/hashicorp/terraform/command/jsonformat/structured/attribute_path" ) // ChangeMap is a Change that represents a Map or an Object type, and has diff --git a/internal/command/jsonformat/structured/sensitive.go b/command/jsonformat/structured/sensitive.go similarity index 96% rename from internal/command/jsonformat/structured/sensitive.go rename to command/jsonformat/structured/sensitive.go index 57e2ff7cf7e8..1e9098ffe096 100644 --- a/internal/command/jsonformat/structured/sensitive.go +++ b/command/jsonformat/structured/sensitive.go @@ -1,8 +1,8 @@ package structured import ( - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/command/jsonformat/computed" + "github.com/hashicorp/terraform/plans" ) type ProcessSensitiveInner func(change Change) computed.Diff diff --git a/internal/command/jsonformat/structured/slice.go b/command/jsonformat/structured/slice.go similarity index 97% rename from internal/command/jsonformat/structured/slice.go rename to command/jsonformat/structured/slice.go index ae7467d60423..9ed5da354ca0 100644 --- a/internal/command/jsonformat/structured/slice.go +++ b/command/jsonformat/structured/slice.go @@ -1,7 +1,7 @@ package structured import ( - "github.com/hashicorp/terraform/internal/command/jsonformat/structured/attribute_path" + "github.com/hashicorp/terraform/command/jsonformat/structured/attribute_path" ) // ChangeSlice is a Change that represents a Tuple, Set, or List type, and has diff --git a/internal/command/jsonformat/structured/unknown.go b/command/jsonformat/structured/unknown.go similarity index 97% rename from internal/command/jsonformat/structured/unknown.go rename to command/jsonformat/structured/unknown.go index 8a3ad386bc6e..fe61582e3a65 100644 --- a/internal/command/jsonformat/structured/unknown.go +++ b/command/jsonformat/structured/unknown.go @@ -1,7 +1,7 @@ package structured import ( - "github.com/hashicorp/terraform/internal/command/jsonformat/computed" + "github.com/hashicorp/terraform/command/jsonformat/computed" ) type ProcessUnknown func(current Change) computed.Diff diff --git a/internal/command/jsonfunction/function.go b/command/jsonfunction/function.go similarity index 98% rename from internal/command/jsonfunction/function.go rename to command/jsonfunction/function.go index 99a78c92cf14..d72e464d6f45 100644 --- a/internal/command/jsonfunction/function.go +++ b/command/jsonfunction/function.go @@ -4,7 +4,7 @@ import ( "encoding/json" "fmt" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" "github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty/function" ) diff --git a/internal/command/jsonfunction/function_test.go b/command/jsonfunction/function_test.go similarity index 100% rename from internal/command/jsonfunction/function_test.go rename to command/jsonfunction/function_test.go diff --git a/internal/command/jsonfunction/parameter.go b/command/jsonfunction/parameter.go similarity index 100% rename from internal/command/jsonfunction/parameter.go rename to command/jsonfunction/parameter.go diff --git a/internal/command/jsonfunction/parameter_test.go b/command/jsonfunction/parameter_test.go similarity index 100% rename from internal/command/jsonfunction/parameter_test.go rename to command/jsonfunction/parameter_test.go diff --git a/internal/command/jsonfunction/return_type.go b/command/jsonfunction/return_type.go similarity index 100% rename from internal/command/jsonfunction/return_type.go rename to command/jsonfunction/return_type.go diff --git a/internal/command/jsonplan/doc.go b/command/jsonplan/doc.go similarity index 100% rename from internal/command/jsonplan/doc.go rename to command/jsonplan/doc.go diff --git a/internal/command/jsonplan/module.go b/command/jsonplan/module.go similarity index 100% rename from internal/command/jsonplan/module.go rename to command/jsonplan/module.go diff --git a/internal/command/jsonplan/plan.go b/command/jsonplan/plan.go similarity index 98% rename from internal/command/jsonplan/plan.go rename to command/jsonplan/plan.go index fca01a1d28a7..3c5d7f3404cf 100644 --- a/internal/command/jsonplan/plan.go +++ b/command/jsonplan/plan.go @@ -9,15 +9,15 @@ import ( "github.com/zclconf/go-cty/cty" ctyjson "github.com/zclconf/go-cty/cty/json" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/command/jsonchecks" - "github.com/hashicorp/terraform/internal/command/jsonconfig" - "github.com/hashicorp/terraform/internal/command/jsonstate" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/statefile" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/command/jsonchecks" + "github.com/hashicorp/terraform/command/jsonconfig" + "github.com/hashicorp/terraform/command/jsonstate" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/statefile" + "github.com/hashicorp/terraform/terraform" "github.com/hashicorp/terraform/version" ) diff --git a/internal/command/jsonplan/plan_test.go b/command/jsonplan/plan_test.go similarity index 99% rename from internal/command/jsonplan/plan_test.go rename to command/jsonplan/plan_test.go index abb6ea29d9dd..27212dbc258f 100644 --- a/internal/command/jsonplan/plan_test.go +++ b/command/jsonplan/plan_test.go @@ -8,8 +8,8 @@ import ( "github.com/google/go-cmp/cmp" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/plans" ) func TestOmitUnknowns(t *testing.T) { diff --git a/internal/command/jsonplan/resource.go b/command/jsonplan/resource.go similarity index 98% rename from internal/command/jsonplan/resource.go rename to command/jsonplan/resource.go index 86ca1233ab3b..336fa1e0c137 100644 --- a/internal/command/jsonplan/resource.go +++ b/command/jsonplan/resource.go @@ -3,7 +3,7 @@ package jsonplan import ( "encoding/json" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) // Resource is the representation of a resource in the json plan diff --git a/internal/command/jsonplan/values.go b/command/jsonplan/values.go similarity index 96% rename from internal/command/jsonplan/values.go rename to command/jsonplan/values.go index f727f8a1d4a5..80824bf50c98 100644 --- a/internal/command/jsonplan/values.go +++ b/command/jsonplan/values.go @@ -8,12 +8,12 @@ import ( "github.com/zclconf/go-cty/cty" ctyjson "github.com/zclconf/go-cty/cty/json" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/command/jsonstate" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/command/jsonstate" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/terraform" ) // stateValues is the common representation of resolved values for both the diff --git a/internal/command/jsonplan/values_test.go b/command/jsonplan/values_test.go similarity index 97% rename from internal/command/jsonplan/values_test.go rename to command/jsonplan/values_test.go index 30b22429aec5..f2b374623418 100644 --- a/internal/command/jsonplan/values_test.go +++ b/command/jsonplan/values_test.go @@ -5,10 +5,10 @@ import ( "reflect" "testing" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/terraform" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/command/jsonprovider/attribute.go b/command/jsonprovider/attribute.go similarity index 96% rename from internal/command/jsonprovider/attribute.go rename to command/jsonprovider/attribute.go index 61deb9c60736..630dea63bcea 100644 --- a/internal/command/jsonprovider/attribute.go +++ b/command/jsonprovider/attribute.go @@ -3,7 +3,7 @@ package jsonprovider import ( "encoding/json" - "github.com/hashicorp/terraform/internal/configs/configschema" + "github.com/hashicorp/terraform/configs/configschema" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/command/jsonprovider/attribute_test.go b/command/jsonprovider/attribute_test.go similarity index 93% rename from internal/command/jsonprovider/attribute_test.go rename to command/jsonprovider/attribute_test.go index f79c5f7cdbdb..887b90104522 100644 --- a/internal/command/jsonprovider/attribute_test.go +++ b/command/jsonprovider/attribute_test.go @@ -7,7 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/configs/configschema" + "github.com/hashicorp/terraform/configs/configschema" ) func TestMarshalAttribute(t *testing.T) { diff --git a/internal/command/jsonprovider/block.go b/command/jsonprovider/block.go similarity index 97% rename from internal/command/jsonprovider/block.go rename to command/jsonprovider/block.go index e9fdcfb3eabf..82afdd85fe60 100644 --- a/internal/command/jsonprovider/block.go +++ b/command/jsonprovider/block.go @@ -1,7 +1,7 @@ package jsonprovider import ( - "github.com/hashicorp/terraform/internal/configs/configschema" + "github.com/hashicorp/terraform/configs/configschema" ) type Block struct { diff --git a/internal/command/jsonprovider/block_test.go b/command/jsonprovider/block_test.go similarity index 96% rename from internal/command/jsonprovider/block_test.go rename to command/jsonprovider/block_test.go index dea72390f506..9090429049e4 100644 --- a/internal/command/jsonprovider/block_test.go +++ b/command/jsonprovider/block_test.go @@ -7,7 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/configs/configschema" + "github.com/hashicorp/terraform/configs/configschema" ) func TestMarshalBlock(t *testing.T) { diff --git a/internal/command/jsonprovider/doc.go b/command/jsonprovider/doc.go similarity index 100% rename from internal/command/jsonprovider/doc.go rename to command/jsonprovider/doc.go diff --git a/internal/command/jsonprovider/provider.go b/command/jsonprovider/provider.go similarity index 97% rename from internal/command/jsonprovider/provider.go rename to command/jsonprovider/provider.go index caf42624bf38..c26d496f36f8 100644 --- a/internal/command/jsonprovider/provider.go +++ b/command/jsonprovider/provider.go @@ -3,7 +3,7 @@ package jsonprovider import ( "encoding/json" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/terraform" ) // FormatVersion represents the version of the json format and will be diff --git a/internal/command/jsonprovider/provider_test.go b/command/jsonprovider/provider_test.go similarity index 97% rename from internal/command/jsonprovider/provider_test.go rename to command/jsonprovider/provider_test.go index b849c37b8293..51f2dea93857 100644 --- a/internal/command/jsonprovider/provider_test.go +++ b/command/jsonprovider/provider_test.go @@ -7,8 +7,8 @@ import ( "github.com/google/go-cmp/cmp" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/terraform" ) func TestMarshalProvider(t *testing.T) { diff --git a/internal/command/jsonprovider/schema.go b/command/jsonprovider/schema.go similarity index 92% rename from internal/command/jsonprovider/schema.go rename to command/jsonprovider/schema.go index c33962a1639a..d345ce2fc52f 100644 --- a/internal/command/jsonprovider/schema.go +++ b/command/jsonprovider/schema.go @@ -1,7 +1,7 @@ package jsonprovider import ( - "github.com/hashicorp/terraform/internal/configs/configschema" + "github.com/hashicorp/terraform/configs/configschema" ) type Schema struct { diff --git a/internal/command/jsonprovider/schema_test.go b/command/jsonprovider/schema_test.go similarity index 92% rename from internal/command/jsonprovider/schema_test.go rename to command/jsonprovider/schema_test.go index d4fae307d5d1..6eba1675b7cc 100644 --- a/internal/command/jsonprovider/schema_test.go +++ b/command/jsonprovider/schema_test.go @@ -5,7 +5,7 @@ import ( "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/configs/configschema" + "github.com/hashicorp/terraform/configs/configschema" ) func TestMarshalSchemas(t *testing.T) { diff --git a/internal/command/jsonstate/doc.go b/command/jsonstate/doc.go similarity index 100% rename from internal/command/jsonstate/doc.go rename to command/jsonstate/doc.go diff --git a/internal/command/jsonstate/state.go b/command/jsonstate/state.go similarity index 97% rename from internal/command/jsonstate/state.go rename to command/jsonstate/state.go index 5cd4793d02e0..59ff05416a7f 100644 --- a/internal/command/jsonstate/state.go +++ b/command/jsonstate/state.go @@ -8,12 +8,12 @@ import ( "github.com/zclconf/go-cty/cty" ctyjson "github.com/zclconf/go-cty/cty/json" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/command/jsonchecks" - "github.com/hashicorp/terraform/internal/lang/marks" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/statefile" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/command/jsonchecks" + "github.com/hashicorp/terraform/lang/marks" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/statefile" + "github.com/hashicorp/terraform/terraform" ) const ( diff --git a/internal/command/jsonstate/state_test.go b/command/jsonstate/state_test.go similarity index 98% rename from internal/command/jsonstate/state_test.go rename to command/jsonstate/state_test.go index 60b234185ce7..4bc1971ed783 100644 --- a/internal/command/jsonstate/state_test.go +++ b/command/jsonstate/state_test.go @@ -8,11 +8,11 @@ import ( "github.com/google/go-cmp/cmp" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/lang/marks" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/lang/marks" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/terraform" ) func TestMarshalOutputs(t *testing.T) { diff --git a/internal/command/login.go b/command/login.go similarity index 99% rename from internal/command/login.go rename to command/login.go index 6b1d8bddd4d2..74b53571d04d 100644 --- a/internal/command/login.go +++ b/command/login.go @@ -20,11 +20,11 @@ import ( svchost "github.com/hashicorp/terraform-svchost" svcauth "github.com/hashicorp/terraform-svchost/auth" "github.com/hashicorp/terraform-svchost/disco" - "github.com/hashicorp/terraform/internal/command/cliconfig" - "github.com/hashicorp/terraform/internal/httpclient" - "github.com/hashicorp/terraform/internal/logging" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/command/cliconfig" + "github.com/hashicorp/terraform/httpclient" + "github.com/hashicorp/terraform/logging" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" uuid "github.com/hashicorp/go-uuid" "golang.org/x/oauth2" diff --git a/internal/command/login_test.go b/command/login_test.go similarity index 96% rename from internal/command/login_test.go rename to command/login_test.go index b612b7bbedec..da93327ea620 100644 --- a/internal/command/login_test.go +++ b/command/login_test.go @@ -11,11 +11,11 @@ import ( svchost "github.com/hashicorp/terraform-svchost" "github.com/hashicorp/terraform-svchost/disco" - "github.com/hashicorp/terraform/internal/command/cliconfig" - oauthserver "github.com/hashicorp/terraform/internal/command/testdata/login-oauth-server" - tfeserver "github.com/hashicorp/terraform/internal/command/testdata/login-tfe-server" - "github.com/hashicorp/terraform/internal/command/webbrowser" - "github.com/hashicorp/terraform/internal/httpclient" + "github.com/hashicorp/terraform/command/cliconfig" + oauthserver "github.com/hashicorp/terraform/command/testdata/login-oauth-server" + tfeserver "github.com/hashicorp/terraform/command/testdata/login-tfe-server" + "github.com/hashicorp/terraform/command/webbrowser" + "github.com/hashicorp/terraform/httpclient" "github.com/hashicorp/terraform/version" ) diff --git a/internal/command/logout.go b/command/logout.go similarity index 97% rename from internal/command/logout.go rename to command/logout.go index 904ccc5b0628..5c510876ee82 100644 --- a/internal/command/logout.go +++ b/command/logout.go @@ -6,8 +6,8 @@ import ( "strings" svchost "github.com/hashicorp/terraform-svchost" - "github.com/hashicorp/terraform/internal/command/cliconfig" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/command/cliconfig" + "github.com/hashicorp/terraform/tfdiags" ) // LogoutCommand is a Command implementation which removes stored credentials diff --git a/internal/command/logout_test.go b/command/logout_test.go similarity index 97% rename from internal/command/logout_test.go rename to command/logout_test.go index 6f2511ee7497..2fbff18f2342 100644 --- a/internal/command/logout_test.go +++ b/command/logout_test.go @@ -9,7 +9,7 @@ import ( svchost "github.com/hashicorp/terraform-svchost" svcauth "github.com/hashicorp/terraform-svchost/auth" "github.com/hashicorp/terraform-svchost/disco" - "github.com/hashicorp/terraform/internal/command/cliconfig" + "github.com/hashicorp/terraform/command/cliconfig" ) func TestLogout(t *testing.T) { diff --git a/internal/command/meta.go b/command/meta.go similarity index 96% rename from internal/command/meta.go rename to command/meta.go index 884cefaad00b..00e02b7f6ea3 100644 --- a/internal/command/meta.go +++ b/command/meta.go @@ -19,24 +19,24 @@ import ( "github.com/mitchellh/cli" "github.com/mitchellh/colorstring" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/backend/local" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/format" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/command/webbrowser" - "github.com/hashicorp/terraform/internal/command/workdir" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configload" - "github.com/hashicorp/terraform/internal/getproviders" - legacy "github.com/hashicorp/terraform/internal/legacy/terraform" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/provisioners" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/terminal" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/backend/local" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/format" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/command/webbrowser" + "github.com/hashicorp/terraform/command/workdir" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/getproviders" + legacy "github.com/hashicorp/terraform/legacy/terraform" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/provisioners" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/terminal" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" ) // Meta are the meta-options that are available on all or most commands. diff --git a/internal/command/meta_backend.go b/command/meta_backend.go similarity index 98% rename from internal/command/meta_backend.go rename to command/meta_backend.go index f61563d81544..0240fe6175a3 100644 --- a/internal/command/meta_backend.go +++ b/command/meta_backend.go @@ -16,22 +16,22 @@ import ( "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hcldec" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/cloud" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/clistate" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/cloud" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/clistate" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" "github.com/zclconf/go-cty/cty" ctyjson "github.com/zclconf/go-cty/cty/json" - backendInit "github.com/hashicorp/terraform/internal/backend/init" - backendLocal "github.com/hashicorp/terraform/internal/backend/local" - legacy "github.com/hashicorp/terraform/internal/legacy/terraform" + backendInit "github.com/hashicorp/terraform/backend/init" + backendLocal "github.com/hashicorp/terraform/backend/local" + legacy "github.com/hashicorp/terraform/legacy/terraform" ) // BackendOpts are the options used to initialize a backend.Backend. diff --git a/internal/command/meta_backend_migrate.go b/command/meta_backend_migrate.go similarity index 98% rename from internal/command/meta_backend_migrate.go rename to command/meta_backend_migrate.go index 9df931c09714..e96505e3723f 100644 --- a/internal/command/meta_backend_migrate.go +++ b/command/meta_backend_migrate.go @@ -12,15 +12,15 @@ import ( "sort" "strings" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/backend/remote" - "github.com/hashicorp/terraform/internal/cloud" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/clistate" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/backend/remote" + "github.com/hashicorp/terraform/cloud" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/clistate" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/terraform" ) type backendMigrateOpts struct { diff --git a/internal/command/meta_backend_migrate_test.go b/command/meta_backend_migrate_test.go similarity index 100% rename from internal/command/meta_backend_migrate_test.go rename to command/meta_backend_migrate_test.go diff --git a/internal/command/meta_backend_test.go b/command/meta_backend_test.go similarity index 98% rename from internal/command/meta_backend_test.go rename to command/meta_backend_test.go index 2fa61b618f7f..297cd03e562e 100644 --- a/internal/command/meta_backend_test.go +++ b/command/meta_backend_test.go @@ -9,20 +9,20 @@ import ( "strings" "testing" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/copy" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/statefile" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/copy" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/statefile" + "github.com/hashicorp/terraform/states/statemgr" "github.com/mitchellh/cli" "github.com/zclconf/go-cty/cty" - backendInit "github.com/hashicorp/terraform/internal/backend/init" - backendLocal "github.com/hashicorp/terraform/internal/backend/local" - backendInmem "github.com/hashicorp/terraform/internal/backend/remote-state/inmem" + backendInit "github.com/hashicorp/terraform/backend/init" + backendLocal "github.com/hashicorp/terraform/backend/local" + backendInmem "github.com/hashicorp/terraform/backend/remote-state/inmem" ) // Test empty directory with no config/state creates a local state. diff --git a/internal/command/meta_config.go b/command/meta_config.go similarity index 97% rename from internal/command/meta_config.go rename to command/meta_config.go index 349a791365cd..f6618bd27b2a 100644 --- a/internal/command/meta_config.go +++ b/command/meta_config.go @@ -9,13 +9,13 @@ import ( "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configload" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/initwd" - "github.com/hashicorp/terraform/internal/registry" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/initwd" + "github.com/hashicorp/terraform/registry" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" "github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty/convert" ) diff --git a/internal/command/meta_dependencies.go b/command/meta_dependencies.go similarity index 97% rename from internal/command/meta_dependencies.go rename to command/meta_dependencies.go index 1b0cb97f8df8..1e4267dfbbec 100644 --- a/internal/command/meta_dependencies.go +++ b/command/meta_dependencies.go @@ -4,8 +4,8 @@ import ( "log" "os" - "github.com/hashicorp/terraform/internal/depsfile" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/depsfile" + "github.com/hashicorp/terraform/tfdiags" ) // dependenclyLockFilename is the filename of the dependency lock file. diff --git a/internal/command/meta_new.go b/command/meta_new.go similarity index 94% rename from internal/command/meta_new.go rename to command/meta_new.go index b89760a4c06b..a308a11e6647 100644 --- a/internal/command/meta_new.go +++ b/command/meta_new.go @@ -4,7 +4,7 @@ import ( "os" "strconv" - "github.com/hashicorp/terraform/internal/plans/planfile" + "github.com/hashicorp/terraform/plans/planfile" ) // NOTE: Temporary file until this branch is cleaned up. diff --git a/internal/command/meta_providers.go b/command/meta_providers.go similarity index 97% rename from internal/command/meta_providers.go rename to command/meta_providers.go index 05e1fe945022..927944838c10 100644 --- a/internal/command/meta_providers.go +++ b/command/meta_providers.go @@ -11,16 +11,16 @@ import ( plugin "github.com/hashicorp/go-plugin" - "github.com/hashicorp/terraform/internal/addrs" - terraformProvider "github.com/hashicorp/terraform/internal/builtin/providers/terraform" - "github.com/hashicorp/terraform/internal/getproviders" - "github.com/hashicorp/terraform/internal/logging" - "github.com/hashicorp/terraform/internal/moduletest" - tfplugin "github.com/hashicorp/terraform/internal/plugin" - tfplugin6 "github.com/hashicorp/terraform/internal/plugin6" - "github.com/hashicorp/terraform/internal/providercache" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + terraformProvider "github.com/hashicorp/terraform/builtin/providers/terraform" + "github.com/hashicorp/terraform/getproviders" + "github.com/hashicorp/terraform/logging" + "github.com/hashicorp/terraform/moduletest" + tfplugin "github.com/hashicorp/terraform/plugin" + tfplugin6 "github.com/hashicorp/terraform/plugin6" + "github.com/hashicorp/terraform/providercache" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/tfdiags" ) // The TF_DISABLE_PLUGIN_TLS environment variable is intended only for use by diff --git a/internal/command/meta_test.go b/command/meta_test.go similarity index 98% rename from internal/command/meta_test.go rename to command/meta_test.go index b8b6c833725b..ace78cf3c0f3 100644 --- a/internal/command/meta_test.go +++ b/command/meta_test.go @@ -11,9 +11,9 @@ import ( "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/backend/local" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/backend/local" + "github.com/hashicorp/terraform/terraform" "github.com/mitchellh/cli" ) diff --git a/internal/command/meta_vars.go b/command/meta_vars.go similarity index 97% rename from internal/command/meta_vars.go rename to command/meta_vars.go index f082daa0c776..2cecba87a099 100644 --- a/internal/command/meta_vars.go +++ b/command/meta_vars.go @@ -9,10 +9,10 @@ import ( "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclsyntax" hcljson "github.com/hashicorp/hcl/v2/json" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" ) // VarEnvPrefix is the prefix for environment variables that represent values diff --git a/internal/command/metadata_command.go b/command/metadata_command.go similarity index 100% rename from internal/command/metadata_command.go rename to command/metadata_command.go diff --git a/internal/command/metadata_functions.go b/command/metadata_functions.go similarity index 94% rename from internal/command/metadata_functions.go rename to command/metadata_functions.go index 43609cc16b18..d8aa4fa87ce3 100644 --- a/internal/command/metadata_functions.go +++ b/command/metadata_functions.go @@ -3,8 +3,8 @@ package command import ( "fmt" - "github.com/hashicorp/terraform/internal/command/jsonfunction" - "github.com/hashicorp/terraform/internal/lang" + "github.com/hashicorp/terraform/command/jsonfunction" + "github.com/hashicorp/terraform/lang" "github.com/zclconf/go-cty/cty/function" ) diff --git a/internal/command/metadata_functions_test.go b/command/metadata_functions_test.go similarity index 100% rename from internal/command/metadata_functions_test.go rename to command/metadata_functions_test.go diff --git a/internal/command/output.go b/command/output.go similarity index 92% rename from internal/command/output.go rename to command/output.go index 0bcde54e8fae..9f5411ac02f1 100644 --- a/internal/command/output.go +++ b/command/output.go @@ -4,10 +4,10 @@ import ( "fmt" "strings" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/tfdiags" ) // OutputCommand is a Command implementation that reads an output diff --git a/internal/command/output_test.go b/command/output_test.go similarity index 98% rename from internal/command/output_test.go rename to command/output_test.go index d3d742c59b51..22e8afe2364b 100644 --- a/internal/command/output_test.go +++ b/command/output_test.go @@ -8,8 +8,8 @@ import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/states" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/states" ) func TestOutput(t *testing.T) { diff --git a/internal/command/plan.go b/command/plan.go similarity index 97% rename from internal/command/plan.go rename to command/plan.go index 674e9a8ff26d..b834a38ffcac 100644 --- a/internal/command/plan.go +++ b/command/plan.go @@ -4,10 +4,10 @@ import ( "fmt" "strings" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/tfdiags" ) // PlanCommand is a Command implementation that compares a Terraform diff --git a/internal/command/plan_test.go b/command/plan_test.go similarity index 98% rename from internal/command/plan_test.go rename to command/plan_test.go index 7ab3324dc39e..e8f60beb10ea 100644 --- a/internal/command/plan_test.go +++ b/command/plan_test.go @@ -16,15 +16,15 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/addrs" - backendinit "github.com/hashicorp/terraform/internal/backend/init" - "github.com/hashicorp/terraform/internal/checks" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + backendinit "github.com/hashicorp/terraform/backend/init" + "github.com/hashicorp/terraform/checks" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" ) func TestPlan(t *testing.T) { diff --git a/internal/command/plugins.go b/command/plugins.go similarity index 91% rename from internal/command/plugins.go rename to command/plugins.go index 7467b09db96a..bfa0df42fd46 100644 --- a/internal/command/plugins.go +++ b/command/plugins.go @@ -10,13 +10,13 @@ import ( plugin "github.com/hashicorp/go-plugin" "github.com/kardianos/osext" - fileprovisioner "github.com/hashicorp/terraform/internal/builtin/provisioners/file" - localexec "github.com/hashicorp/terraform/internal/builtin/provisioners/local-exec" - remoteexec "github.com/hashicorp/terraform/internal/builtin/provisioners/remote-exec" - "github.com/hashicorp/terraform/internal/logging" - tfplugin "github.com/hashicorp/terraform/internal/plugin" - "github.com/hashicorp/terraform/internal/plugin/discovery" - "github.com/hashicorp/terraform/internal/provisioners" + fileprovisioner "github.com/hashicorp/terraform/builtin/provisioners/file" + localexec "github.com/hashicorp/terraform/builtin/provisioners/local-exec" + remoteexec "github.com/hashicorp/terraform/builtin/provisioners/remote-exec" + "github.com/hashicorp/terraform/logging" + tfplugin "github.com/hashicorp/terraform/plugin" + "github.com/hashicorp/terraform/plugin/discovery" + "github.com/hashicorp/terraform/provisioners" ) // NOTE WELL: The logic in this file is primarily about plugin types OTHER THAN diff --git a/internal/command/plugins_lock.go b/command/plugins_lock.go similarity index 100% rename from internal/command/plugins_lock.go rename to command/plugins_lock.go diff --git a/internal/command/plugins_lock_test.go b/command/plugins_lock_test.go similarity index 100% rename from internal/command/plugins_lock_test.go rename to command/plugins_lock_test.go diff --git a/internal/command/plugins_test.go b/command/plugins_test.go similarity index 100% rename from internal/command/plugins_test.go rename to command/plugins_test.go diff --git a/internal/command/providers.go b/command/providers.go similarity index 96% rename from internal/command/providers.go rename to command/providers.go index c55a91774a9f..6a68617efe58 100644 --- a/internal/command/providers.go +++ b/command/providers.go @@ -6,9 +6,9 @@ import ( "github.com/xlab/treeprint" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/getproviders" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/getproviders" + "github.com/hashicorp/terraform/tfdiags" ) // ProvidersCommand is a Command implementation that prints out information diff --git a/internal/command/providers_lock.go b/command/providers_lock.go similarity index 98% rename from internal/command/providers_lock.go rename to command/providers_lock.go index 7dcf20db11b1..6c98b8e569b6 100644 --- a/internal/command/providers_lock.go +++ b/command/providers_lock.go @@ -6,11 +6,11 @@ import ( "net/url" "os" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/depsfile" - "github.com/hashicorp/terraform/internal/getproviders" - "github.com/hashicorp/terraform/internal/providercache" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/depsfile" + "github.com/hashicorp/terraform/getproviders" + "github.com/hashicorp/terraform/providercache" + "github.com/hashicorp/terraform/tfdiags" ) type providersLockChangeType string diff --git a/internal/command/providers_lock_test.go b/command/providers_lock_test.go similarity index 97% rename from internal/command/providers_lock_test.go rename to command/providers_lock_test.go index 5ba792b7e62b..5e38616f5af9 100644 --- a/internal/command/providers_lock_test.go +++ b/command/providers_lock_test.go @@ -8,9 +8,9 @@ import ( "strings" "testing" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/depsfile" - "github.com/hashicorp/terraform/internal/getproviders" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/depsfile" + "github.com/hashicorp/terraform/getproviders" "github.com/mitchellh/cli" ) diff --git a/internal/command/providers_mirror.go b/command/providers_mirror.go similarity index 98% rename from internal/command/providers_mirror.go rename to command/providers_mirror.go index f6ab2258244c..1f131ae12007 100644 --- a/internal/command/providers_mirror.go +++ b/command/providers_mirror.go @@ -10,9 +10,9 @@ import ( "github.com/apparentlymart/go-versions/versions" "github.com/hashicorp/go-getter" - "github.com/hashicorp/terraform/internal/getproviders" - "github.com/hashicorp/terraform/internal/httpclient" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/getproviders" + "github.com/hashicorp/terraform/httpclient" + "github.com/hashicorp/terraform/tfdiags" ) // ProvidersMirrorCommand is a Command implementation that implements the diff --git a/internal/command/providers_mirror_test.go b/command/providers_mirror_test.go similarity index 100% rename from internal/command/providers_mirror_test.go rename to command/providers_mirror_test.go diff --git a/internal/command/providers_schema.go b/command/providers_schema.go similarity index 92% rename from internal/command/providers_schema.go rename to command/providers_schema.go index 61201192c368..f9604ae003e1 100644 --- a/internal/command/providers_schema.go +++ b/command/providers_schema.go @@ -4,10 +4,10 @@ import ( "fmt" "os" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/jsonprovider" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/jsonprovider" + "github.com/hashicorp/terraform/tfdiags" ) // ProvidersCommand is a Command implementation that prints out information diff --git a/internal/command/providers_schema_test.go b/command/providers_schema_test.go similarity index 95% rename from internal/command/providers_schema_test.go rename to command/providers_schema_test.go index 9aa8f810c7a3..75c4652a6357 100644 --- a/internal/command/providers_schema_test.go +++ b/command/providers_schema_test.go @@ -9,9 +9,9 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/terraform" "github.com/mitchellh/cli" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/command/providers_test.go b/command/providers_test.go similarity index 100% rename from internal/command/providers_test.go rename to command/providers_test.go diff --git a/internal/command/push.go b/command/push.go similarity index 95% rename from internal/command/push.go rename to command/push.go index ee1544926d33..27e6d6051fb2 100644 --- a/internal/command/push.go +++ b/command/push.go @@ -3,7 +3,7 @@ package command import ( "strings" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" ) type PushCommand struct { diff --git a/internal/command/refresh.go b/command/refresh.go similarity index 96% rename from internal/command/refresh.go rename to command/refresh.go index 825981f142e9..532ee05aef5e 100644 --- a/internal/command/refresh.go +++ b/command/refresh.go @@ -4,10 +4,10 @@ import ( "fmt" "strings" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/tfdiags" ) // RefreshCommand is a cli.Command implementation that refreshes the state diff --git a/internal/command/refresh_test.go b/command/refresh_test.go similarity index 98% rename from internal/command/refresh_test.go rename to command/refresh_test.go index 1598bbd299c7..3080891572fd 100644 --- a/internal/command/refresh_test.go +++ b/command/refresh_test.go @@ -16,13 +16,13 @@ import ( "github.com/mitchellh/cli" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/statefile" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/statefile" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/tfdiags" ) var equateEmpty = cmpopts.EquateEmpty() diff --git a/internal/command/show.go b/command/show.go similarity index 92% rename from internal/command/show.go rename to command/show.go index 3e58a979a870..4146f98187df 100644 --- a/internal/command/show.go +++ b/command/show.go @@ -5,16 +5,16 @@ import ( "os" "strings" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/plans/planfile" - "github.com/hashicorp/terraform/internal/states/statefile" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/plans/planfile" + "github.com/hashicorp/terraform/states/statefile" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" ) // ShowCommand is a Command implementation that reads and outputs the diff --git a/internal/command/show_test.go b/command/show_test.go similarity index 98% rename from internal/command/show_test.go rename to command/show_test.go index 169b75dc1b4e..7e5224ad5df5 100644 --- a/internal/command/show_test.go +++ b/command/show_test.go @@ -9,13 +9,13 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/terraform" "github.com/hashicorp/terraform/version" "github.com/mitchellh/cli" "github.com/zclconf/go-cty/cty" diff --git a/internal/command/state_command.go b/command/state_command.go similarity index 100% rename from internal/command/state_command.go rename to command/state_command.go diff --git a/internal/command/state_list.go b/command/state_list.go similarity index 96% rename from internal/command/state_list.go rename to command/state_list.go index 54358b28d702..160adb8cd398 100644 --- a/internal/command/state_list.go +++ b/command/state_list.go @@ -4,9 +4,9 @@ import ( "fmt" "strings" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/tfdiags" "github.com/mitchellh/cli" ) diff --git a/internal/command/state_list_test.go b/command/state_list_test.go similarity index 100% rename from internal/command/state_list_test.go rename to command/state_list_test.go diff --git a/internal/command/state_meta.go b/command/state_meta.go similarity index 95% rename from internal/command/state_meta.go rename to command/state_meta.go index 17959f5ff90f..90656a91e6e8 100644 --- a/internal/command/state_meta.go +++ b/command/state_meta.go @@ -5,12 +5,12 @@ import ( "sort" "time" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/tfdiags" - backendLocal "github.com/hashicorp/terraform/internal/backend/local" + backendLocal "github.com/hashicorp/terraform/backend/local" ) // StateMeta is the meta struct that should be embedded in state subcommands. diff --git a/internal/command/state_mv.go b/command/state_mv.go similarity index 97% rename from internal/command/state_mv.go rename to command/state_mv.go index feb650ac886f..1c9776d4d90e 100644 --- a/internal/command/state_mv.go +++ b/command/state_mv.go @@ -4,14 +4,14 @@ import ( "fmt" "strings" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/clistate" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/clistate" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" "github.com/mitchellh/cli" ) diff --git a/internal/command/state_mv_test.go b/command/state_mv_test.go similarity index 99% rename from internal/command/state_mv_test.go rename to command/state_mv_test.go index 00f871f880eb..d68a22afac26 100644 --- a/internal/command/state_mv_test.go +++ b/command/state_mv_test.go @@ -10,8 +10,8 @@ import ( "github.com/google/go-cmp/cmp" "github.com/mitchellh/cli" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/states" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/states" ) func TestStateMv(t *testing.T) { diff --git a/internal/command/state_pull.go b/command/state_pull.go similarity index 94% rename from internal/command/state_pull.go rename to command/state_pull.go index 8872cec65cfa..122ff1d3cbd3 100644 --- a/internal/command/state_pull.go +++ b/command/state_pull.go @@ -5,8 +5,8 @@ import ( "fmt" "strings" - "github.com/hashicorp/terraform/internal/states/statefile" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/states/statefile" + "github.com/hashicorp/terraform/states/statemgr" ) // StatePullCommand is a Command implementation that shows a single resource. diff --git a/internal/command/state_pull_test.go b/command/state_pull_test.go similarity index 100% rename from internal/command/state_pull_test.go rename to command/state_pull_test.go diff --git a/internal/command/state_push.go b/command/state_push.go similarity index 92% rename from internal/command/state_push.go rename to command/state_push.go index c738dc70e36a..769ae0a28564 100644 --- a/internal/command/state_push.go +++ b/command/state_push.go @@ -6,13 +6,13 @@ import ( "os" "strings" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/clistate" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/states/statefile" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/clistate" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/states/statefile" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" "github.com/mitchellh/cli" ) diff --git a/internal/command/state_push_test.go b/command/state_push_test.go similarity index 97% rename from internal/command/state_push_test.go rename to command/state_push_test.go index f79efa9b3b5e..53f1b0568b90 100644 --- a/internal/command/state_push_test.go +++ b/command/state_push_test.go @@ -5,9 +5,9 @@ import ( "strings" "testing" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/backend/remote-state/inmem" - "github.com/hashicorp/terraform/internal/states" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/backend/remote-state/inmem" + "github.com/hashicorp/terraform/states" "github.com/mitchellh/cli" ) diff --git a/internal/command/state_replace_provider.go b/command/state_replace_provider.go similarity index 94% rename from internal/command/state_replace_provider.go rename to command/state_replace_provider.go index 42fdc6255907..56d23f52c5d0 100644 --- a/internal/command/state_replace_provider.go +++ b/command/state_replace_provider.go @@ -4,13 +4,13 @@ import ( "fmt" "strings" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/clistate" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/clistate" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" "github.com/mitchellh/cli" ) diff --git a/internal/command/state_replace_provider_test.go b/command/state_replace_provider_test.go similarity index 99% rename from internal/command/state_replace_provider_test.go rename to command/state_replace_provider_test.go index 9c86cf7797d1..a2576b7eab6c 100644 --- a/internal/command/state_replace_provider_test.go +++ b/command/state_replace_provider_test.go @@ -8,8 +8,8 @@ import ( "github.com/mitchellh/cli" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/states" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/states" ) func TestStateReplaceProvider(t *testing.T) { diff --git a/internal/command/state_rm.go b/command/state_rm.go similarity index 94% rename from internal/command/state_rm.go rename to command/state_rm.go index 77d4b1823b2a..d7957a9a7f46 100644 --- a/internal/command/state_rm.go +++ b/command/state_rm.go @@ -4,12 +4,12 @@ import ( "fmt" "strings" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/clistate" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/clistate" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" "github.com/mitchellh/cli" ) diff --git a/internal/command/state_rm_test.go b/command/state_rm_test.go similarity index 99% rename from internal/command/state_rm_test.go rename to command/state_rm_test.go index 1b58a59677ec..6cae9d5be3d4 100644 --- a/internal/command/state_rm_test.go +++ b/command/state_rm_test.go @@ -8,8 +8,8 @@ import ( "github.com/mitchellh/cli" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/states" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/states" ) func TestStateRm(t *testing.T) { diff --git a/internal/command/state_show.go b/command/state_show.go similarity index 94% rename from internal/command/state_show.go rename to command/state_show.go index 3abd63c48934..63c1d01f0821 100644 --- a/internal/command/state_show.go +++ b/command/state_show.go @@ -5,11 +5,11 @@ import ( "os" "strings" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/format" - "github.com/hashicorp/terraform/internal/states" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/format" + "github.com/hashicorp/terraform/states" "github.com/mitchellh/cli" ) diff --git a/internal/command/state_show_test.go b/command/state_show_test.go similarity index 96% rename from internal/command/state_show_test.go rename to command/state_show_test.go index 3da87c0ecaa1..2ded7ca45d81 100644 --- a/internal/command/state_show_test.go +++ b/command/state_show_test.go @@ -4,10 +4,10 @@ import ( "strings" "testing" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/states" "github.com/mitchellh/cli" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/command/state_test.go b/command/state_test.go similarity index 93% rename from internal/command/state_test.go rename to command/state_test.go index cd2e830125db..a9eddcb00920 100644 --- a/internal/command/state_test.go +++ b/command/state_test.go @@ -6,7 +6,7 @@ import ( "sort" "testing" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/states/statemgr" ) // testStateBackups returns the list of backups in order of creation diff --git a/internal/command/taint.go b/command/taint.go similarity index 95% rename from internal/command/taint.go rename to command/taint.go index e4da31d9b2ef..dba0a98862a7 100644 --- a/internal/command/taint.go +++ b/command/taint.go @@ -4,13 +4,13 @@ import ( "fmt" "strings" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/clistate" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/clistate" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" ) // TaintCommand is a cli.Command implementation that manually taints diff --git a/internal/command/taint_test.go b/command/taint_test.go similarity index 99% rename from internal/command/taint_test.go rename to command/taint_test.go index 001d477082bc..bddf66420a25 100644 --- a/internal/command/taint_test.go +++ b/command/taint_test.go @@ -8,8 +8,8 @@ import ( "github.com/google/go-cmp/cmp" "github.com/mitchellh/cli" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/states" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/states" ) func TestTaint(t *testing.T) { diff --git a/internal/command/test.go b/command/test.go similarity index 97% rename from internal/command/test.go rename to command/test.go index 1f18689f1bc5..b14b86ab0619 100644 --- a/internal/command/test.go +++ b/command/test.go @@ -11,21 +11,21 @@ import ( ctyjson "github.com/zclconf/go-cty/cty/json" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/format" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configload" - "github.com/hashicorp/terraform/internal/depsfile" - "github.com/hashicorp/terraform/internal/initwd" - "github.com/hashicorp/terraform/internal/moduletest" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/providercache" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/format" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/depsfile" + "github.com/hashicorp/terraform/initwd" + "github.com/hashicorp/terraform/moduletest" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/providercache" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" ) // TestCommand is the implementation of "terraform test". diff --git a/internal/command/test_test.go b/command/test_test.go similarity index 97% rename from internal/command/test_test.go rename to command/test_test.go index 17ae6da67ab1..a697d81b93c0 100644 --- a/internal/command/test_test.go +++ b/command/test_test.go @@ -7,8 +7,8 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/terminal" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/terminal" ) // These are the main tests for the "terraform test" command. diff --git a/internal/command/testdata/apply-config-invalid/main.tf b/command/testdata/apply-config-invalid/main.tf similarity index 100% rename from internal/command/testdata/apply-config-invalid/main.tf rename to command/testdata/apply-config-invalid/main.tf diff --git a/internal/command/testdata/apply-destroy-targeted/main.tf b/command/testdata/apply-destroy-targeted/main.tf similarity index 100% rename from internal/command/testdata/apply-destroy-targeted/main.tf rename to command/testdata/apply-destroy-targeted/main.tf diff --git a/internal/command/testdata/apply-error/main.tf b/command/testdata/apply-error/main.tf similarity index 100% rename from internal/command/testdata/apply-error/main.tf rename to command/testdata/apply-error/main.tf diff --git a/internal/command/testdata/apply-input-partial/main.tf b/command/testdata/apply-input-partial/main.tf similarity index 100% rename from internal/command/testdata/apply-input-partial/main.tf rename to command/testdata/apply-input-partial/main.tf diff --git a/internal/command/testdata/apply-input/main.tf b/command/testdata/apply-input/main.tf similarity index 100% rename from internal/command/testdata/apply-input/main.tf rename to command/testdata/apply-input/main.tf diff --git a/internal/command/testdata/apply-plan-no-module/main.tf b/command/testdata/apply-plan-no-module/main.tf similarity index 100% rename from internal/command/testdata/apply-plan-no-module/main.tf rename to command/testdata/apply-plan-no-module/main.tf diff --git a/internal/command/testdata/apply-replace/main.tf b/command/testdata/apply-replace/main.tf similarity index 100% rename from internal/command/testdata/apply-replace/main.tf rename to command/testdata/apply-replace/main.tf diff --git a/internal/command/testdata/apply-sensitive-output/main.tf b/command/testdata/apply-sensitive-output/main.tf similarity index 100% rename from internal/command/testdata/apply-sensitive-output/main.tf rename to command/testdata/apply-sensitive-output/main.tf diff --git a/internal/command/testdata/apply-shutdown/main.tf b/command/testdata/apply-shutdown/main.tf similarity index 100% rename from internal/command/testdata/apply-shutdown/main.tf rename to command/testdata/apply-shutdown/main.tf diff --git a/internal/command/testdata/apply-targeted/main.tf b/command/testdata/apply-targeted/main.tf similarity index 100% rename from internal/command/testdata/apply-targeted/main.tf rename to command/testdata/apply-targeted/main.tf diff --git a/internal/command/testdata/apply-terraform-env/main.tf b/command/testdata/apply-terraform-env/main.tf similarity index 100% rename from internal/command/testdata/apply-terraform-env/main.tf rename to command/testdata/apply-terraform-env/main.tf diff --git a/internal/command/testdata/apply-vars/main.tf b/command/testdata/apply-vars/main.tf similarity index 100% rename from internal/command/testdata/apply-vars/main.tf rename to command/testdata/apply-vars/main.tf diff --git a/internal/command/testdata/apply/main.tf b/command/testdata/apply/main.tf similarity index 100% rename from internal/command/testdata/apply/main.tf rename to command/testdata/apply/main.tf diff --git a/internal/command/testdata/apply/output.jsonlog b/command/testdata/apply/output.jsonlog similarity index 100% rename from internal/command/testdata/apply/output.jsonlog rename to command/testdata/apply/output.jsonlog diff --git a/internal/command/testdata/backend-change-multi-default-to-single/.terraform/terraform.tfstate b/command/testdata/backend-change-multi-default-to-single/.terraform/terraform.tfstate similarity index 100% rename from internal/command/testdata/backend-change-multi-default-to-single/.terraform/terraform.tfstate rename to command/testdata/backend-change-multi-default-to-single/.terraform/terraform.tfstate diff --git a/internal/command/testdata/backend-change-multi-default-to-single/local-state.tfstate b/command/testdata/backend-change-multi-default-to-single/local-state.tfstate similarity index 100% rename from internal/command/testdata/backend-change-multi-default-to-single/local-state.tfstate rename to command/testdata/backend-change-multi-default-to-single/local-state.tfstate diff --git a/internal/command/testdata/backend-change-multi-default-to-single/main.tf b/command/testdata/backend-change-multi-default-to-single/main.tf similarity index 100% rename from internal/command/testdata/backend-change-multi-default-to-single/main.tf rename to command/testdata/backend-change-multi-default-to-single/main.tf diff --git a/internal/command/testdata/backend-change-multi-to-multi/.terraform/terraform.tfstate b/command/testdata/backend-change-multi-to-multi/.terraform/terraform.tfstate similarity index 100% rename from internal/command/testdata/backend-change-multi-to-multi/.terraform/terraform.tfstate rename to command/testdata/backend-change-multi-to-multi/.terraform/terraform.tfstate diff --git a/internal/command/testdata/backend-change-multi-to-multi/local-state.tfstate b/command/testdata/backend-change-multi-to-multi/local-state.tfstate similarity index 100% rename from internal/command/testdata/backend-change-multi-to-multi/local-state.tfstate rename to command/testdata/backend-change-multi-to-multi/local-state.tfstate diff --git a/internal/command/testdata/backend-change-multi-to-multi/main.tf b/command/testdata/backend-change-multi-to-multi/main.tf similarity index 100% rename from internal/command/testdata/backend-change-multi-to-multi/main.tf rename to command/testdata/backend-change-multi-to-multi/main.tf diff --git a/internal/command/testdata/backend-change-multi-to-multi/terraform.tfstate.d/env2/terraform.tfstate b/command/testdata/backend-change-multi-to-multi/terraform.tfstate.d/env2/terraform.tfstate similarity index 100% rename from internal/command/testdata/backend-change-multi-to-multi/terraform.tfstate.d/env2/terraform.tfstate rename to command/testdata/backend-change-multi-to-multi/terraform.tfstate.d/env2/terraform.tfstate diff --git a/internal/command/testdata/backend-change-multi-to-no-default-with-default/.terraform/terraform.tfstate b/command/testdata/backend-change-multi-to-no-default-with-default/.terraform/terraform.tfstate similarity index 100% rename from internal/command/testdata/backend-change-multi-to-no-default-with-default/.terraform/terraform.tfstate rename to command/testdata/backend-change-multi-to-no-default-with-default/.terraform/terraform.tfstate diff --git a/internal/command/testdata/backend-change-multi-to-no-default-with-default/local-state.tfstate b/command/testdata/backend-change-multi-to-no-default-with-default/local-state.tfstate similarity index 100% rename from internal/command/testdata/backend-change-multi-to-no-default-with-default/local-state.tfstate rename to command/testdata/backend-change-multi-to-no-default-with-default/local-state.tfstate diff --git a/internal/command/testdata/backend-change-multi-to-no-default-with-default/main.tf b/command/testdata/backend-change-multi-to-no-default-with-default/main.tf similarity index 100% rename from internal/command/testdata/backend-change-multi-to-no-default-with-default/main.tf rename to command/testdata/backend-change-multi-to-no-default-with-default/main.tf diff --git a/internal/command/testdata/backend-change-multi-to-no-default-with-default/terraform.tfstate.d/env2/terraform.tfstate b/command/testdata/backend-change-multi-to-no-default-with-default/terraform.tfstate.d/env2/terraform.tfstate similarity index 100% rename from internal/command/testdata/backend-change-multi-to-no-default-with-default/terraform.tfstate.d/env2/terraform.tfstate rename to command/testdata/backend-change-multi-to-no-default-with-default/terraform.tfstate.d/env2/terraform.tfstate diff --git a/internal/command/testdata/backend-change-multi-to-no-default-without-default/.terraform/terraform.tfstate b/command/testdata/backend-change-multi-to-no-default-without-default/.terraform/terraform.tfstate similarity index 100% rename from internal/command/testdata/backend-change-multi-to-no-default-without-default/.terraform/terraform.tfstate rename to command/testdata/backend-change-multi-to-no-default-without-default/.terraform/terraform.tfstate diff --git a/internal/command/testdata/backend-change-multi-to-no-default-without-default/main.tf b/command/testdata/backend-change-multi-to-no-default-without-default/main.tf similarity index 100% rename from internal/command/testdata/backend-change-multi-to-no-default-without-default/main.tf rename to command/testdata/backend-change-multi-to-no-default-without-default/main.tf diff --git a/internal/command/testdata/backend-change-multi-to-no-default-without-default/terraform.tfstate.d/env2/terraform.tfstate b/command/testdata/backend-change-multi-to-no-default-without-default/terraform.tfstate.d/env2/terraform.tfstate similarity index 100% rename from internal/command/testdata/backend-change-multi-to-no-default-without-default/terraform.tfstate.d/env2/terraform.tfstate rename to command/testdata/backend-change-multi-to-no-default-without-default/terraform.tfstate.d/env2/terraform.tfstate diff --git a/internal/command/testdata/backend-change-multi-to-single/.terraform/environment b/command/testdata/backend-change-multi-to-single/.terraform/environment similarity index 100% rename from internal/command/testdata/backend-change-multi-to-single/.terraform/environment rename to command/testdata/backend-change-multi-to-single/.terraform/environment diff --git a/internal/command/testdata/backend-change-multi-to-single/.terraform/terraform.tfstate b/command/testdata/backend-change-multi-to-single/.terraform/terraform.tfstate similarity index 100% rename from internal/command/testdata/backend-change-multi-to-single/.terraform/terraform.tfstate rename to command/testdata/backend-change-multi-to-single/.terraform/terraform.tfstate diff --git a/internal/command/testdata/backend-change-multi-to-single/main.tf b/command/testdata/backend-change-multi-to-single/main.tf similarity index 100% rename from internal/command/testdata/backend-change-multi-to-single/main.tf rename to command/testdata/backend-change-multi-to-single/main.tf diff --git a/internal/command/testdata/backend-change-multi-to-single/terraform.tfstate.d/env1/terraform.tfstate b/command/testdata/backend-change-multi-to-single/terraform.tfstate.d/env1/terraform.tfstate similarity index 100% rename from internal/command/testdata/backend-change-multi-to-single/terraform.tfstate.d/env1/terraform.tfstate rename to command/testdata/backend-change-multi-to-single/terraform.tfstate.d/env1/terraform.tfstate diff --git a/internal/command/testdata/backend-change-multi-to-single/terraform.tfstate.d/env2/terraform.tfstate b/command/testdata/backend-change-multi-to-single/terraform.tfstate.d/env2/terraform.tfstate similarity index 100% rename from internal/command/testdata/backend-change-multi-to-single/terraform.tfstate.d/env2/terraform.tfstate rename to command/testdata/backend-change-multi-to-single/terraform.tfstate.d/env2/terraform.tfstate diff --git a/internal/command/testdata/backend-change-single-to-single/.terraform/terraform.tfstate b/command/testdata/backend-change-single-to-single/.terraform/terraform.tfstate similarity index 100% rename from internal/command/testdata/backend-change-single-to-single/.terraform/terraform.tfstate rename to command/testdata/backend-change-single-to-single/.terraform/terraform.tfstate diff --git a/internal/command/testdata/backend-change-single-to-single/local-state.tfstate b/command/testdata/backend-change-single-to-single/local-state.tfstate similarity index 100% rename from internal/command/testdata/backend-change-single-to-single/local-state.tfstate rename to command/testdata/backend-change-single-to-single/local-state.tfstate diff --git a/internal/command/testdata/backend-change-single-to-single/main.tf b/command/testdata/backend-change-single-to-single/main.tf similarity index 100% rename from internal/command/testdata/backend-change-single-to-single/main.tf rename to command/testdata/backend-change-single-to-single/main.tf diff --git a/internal/command/testdata/backend-change/.terraform/terraform.tfstate b/command/testdata/backend-change/.terraform/terraform.tfstate similarity index 100% rename from internal/command/testdata/backend-change/.terraform/terraform.tfstate rename to command/testdata/backend-change/.terraform/terraform.tfstate diff --git a/internal/command/testdata/backend-change/local-state.tfstate b/command/testdata/backend-change/local-state.tfstate similarity index 100% rename from internal/command/testdata/backend-change/local-state.tfstate rename to command/testdata/backend-change/local-state.tfstate diff --git a/internal/command/testdata/backend-change/main.tf b/command/testdata/backend-change/main.tf similarity index 100% rename from internal/command/testdata/backend-change/main.tf rename to command/testdata/backend-change/main.tf diff --git a/internal/command/testdata/backend-changed-with-legacy/.terraform/terraform.tfstate b/command/testdata/backend-changed-with-legacy/.terraform/terraform.tfstate similarity index 100% rename from internal/command/testdata/backend-changed-with-legacy/.terraform/terraform.tfstate rename to command/testdata/backend-changed-with-legacy/.terraform/terraform.tfstate diff --git a/internal/command/testdata/backend-changed-with-legacy/local-state-old.tfstate b/command/testdata/backend-changed-with-legacy/local-state-old.tfstate similarity index 100% rename from internal/command/testdata/backend-changed-with-legacy/local-state-old.tfstate rename to command/testdata/backend-changed-with-legacy/local-state-old.tfstate diff --git a/internal/command/testdata/backend-changed-with-legacy/local-state.tfstate b/command/testdata/backend-changed-with-legacy/local-state.tfstate similarity index 100% rename from internal/command/testdata/backend-changed-with-legacy/local-state.tfstate rename to command/testdata/backend-changed-with-legacy/local-state.tfstate diff --git a/internal/command/testdata/backend-changed-with-legacy/main.tf b/command/testdata/backend-changed-with-legacy/main.tf similarity index 100% rename from internal/command/testdata/backend-changed-with-legacy/main.tf rename to command/testdata/backend-changed-with-legacy/main.tf diff --git a/internal/command/testdata/backend-from-state/terraform.tfstate b/command/testdata/backend-from-state/terraform.tfstate similarity index 100% rename from internal/command/testdata/backend-from-state/terraform.tfstate rename to command/testdata/backend-from-state/terraform.tfstate diff --git a/internal/command/testdata/backend-inmem-locked/main.tf b/command/testdata/backend-inmem-locked/main.tf similarity index 100% rename from internal/command/testdata/backend-inmem-locked/main.tf rename to command/testdata/backend-inmem-locked/main.tf diff --git a/internal/command/testdata/backend-new-interp/main.tf b/command/testdata/backend-new-interp/main.tf similarity index 100% rename from internal/command/testdata/backend-new-interp/main.tf rename to command/testdata/backend-new-interp/main.tf diff --git a/internal/command/testdata/backend-new-legacy/.terraform/terraform.tfstate b/command/testdata/backend-new-legacy/.terraform/terraform.tfstate similarity index 100% rename from internal/command/testdata/backend-new-legacy/.terraform/terraform.tfstate rename to command/testdata/backend-new-legacy/.terraform/terraform.tfstate diff --git a/internal/command/testdata/backend-new-legacy/local-state-old.tfstate b/command/testdata/backend-new-legacy/local-state-old.tfstate similarity index 100% rename from internal/command/testdata/backend-new-legacy/local-state-old.tfstate rename to command/testdata/backend-new-legacy/local-state-old.tfstate diff --git a/internal/command/testdata/backend-new-legacy/main.tf b/command/testdata/backend-new-legacy/main.tf similarity index 100% rename from internal/command/testdata/backend-new-legacy/main.tf rename to command/testdata/backend-new-legacy/main.tf diff --git a/internal/command/testdata/backend-new-migrate-existing/local-state.tfstate b/command/testdata/backend-new-migrate-existing/local-state.tfstate similarity index 100% rename from internal/command/testdata/backend-new-migrate-existing/local-state.tfstate rename to command/testdata/backend-new-migrate-existing/local-state.tfstate diff --git a/internal/command/testdata/backend-new-migrate-existing/main.tf b/command/testdata/backend-new-migrate-existing/main.tf similarity index 100% rename from internal/command/testdata/backend-new-migrate-existing/main.tf rename to command/testdata/backend-new-migrate-existing/main.tf diff --git a/internal/command/testdata/backend-new-migrate-existing/terraform.tfstate b/command/testdata/backend-new-migrate-existing/terraform.tfstate similarity index 100% rename from internal/command/testdata/backend-new-migrate-existing/terraform.tfstate rename to command/testdata/backend-new-migrate-existing/terraform.tfstate diff --git a/internal/command/testdata/backend-new-migrate/main.tf b/command/testdata/backend-new-migrate/main.tf similarity index 100% rename from internal/command/testdata/backend-new-migrate/main.tf rename to command/testdata/backend-new-migrate/main.tf diff --git a/internal/command/testdata/backend-new-migrate/terraform.tfstate b/command/testdata/backend-new-migrate/terraform.tfstate similarity index 100% rename from internal/command/testdata/backend-new-migrate/terraform.tfstate rename to command/testdata/backend-new-migrate/terraform.tfstate diff --git a/internal/command/testdata/backend-new/main.tf b/command/testdata/backend-new/main.tf similarity index 100% rename from internal/command/testdata/backend-new/main.tf rename to command/testdata/backend-new/main.tf diff --git a/internal/command/testdata/backend-plan-backend-empty-config/.terraform/terraform.tfstate b/command/testdata/backend-plan-backend-empty-config/.terraform/terraform.tfstate similarity index 100% rename from internal/command/testdata/backend-plan-backend-empty-config/.terraform/terraform.tfstate rename to command/testdata/backend-plan-backend-empty-config/.terraform/terraform.tfstate diff --git a/internal/command/testdata/backend-plan-backend-empty-config/local-state.tfstate b/command/testdata/backend-plan-backend-empty-config/local-state.tfstate similarity index 100% rename from internal/command/testdata/backend-plan-backend-empty-config/local-state.tfstate rename to command/testdata/backend-plan-backend-empty-config/local-state.tfstate diff --git a/internal/command/testdata/backend-plan-backend-empty-config/main.tf b/command/testdata/backend-plan-backend-empty-config/main.tf similarity index 100% rename from internal/command/testdata/backend-plan-backend-empty-config/main.tf rename to command/testdata/backend-plan-backend-empty-config/main.tf diff --git a/internal/command/testdata/backend-plan-backend-empty/readme.txt b/command/testdata/backend-plan-backend-empty/readme.txt similarity index 100% rename from internal/command/testdata/backend-plan-backend-empty/readme.txt rename to command/testdata/backend-plan-backend-empty/readme.txt diff --git a/internal/command/testdata/backend-plan-backend-match/local-state.tfstate b/command/testdata/backend-plan-backend-match/local-state.tfstate similarity index 100% rename from internal/command/testdata/backend-plan-backend-match/local-state.tfstate rename to command/testdata/backend-plan-backend-match/local-state.tfstate diff --git a/internal/command/testdata/backend-plan-backend-match/readme.txt b/command/testdata/backend-plan-backend-match/readme.txt similarity index 100% rename from internal/command/testdata/backend-plan-backend-match/readme.txt rename to command/testdata/backend-plan-backend-match/readme.txt diff --git a/internal/command/testdata/backend-plan-backend-mismatch/local-state.tfstate b/command/testdata/backend-plan-backend-mismatch/local-state.tfstate similarity index 100% rename from internal/command/testdata/backend-plan-backend-mismatch/local-state.tfstate rename to command/testdata/backend-plan-backend-mismatch/local-state.tfstate diff --git a/internal/command/testdata/backend-plan-legacy-data/local-state.tfstate b/command/testdata/backend-plan-legacy-data/local-state.tfstate similarity index 100% rename from internal/command/testdata/backend-plan-legacy-data/local-state.tfstate rename to command/testdata/backend-plan-legacy-data/local-state.tfstate diff --git a/internal/command/testdata/backend-plan-legacy-data/main.tf b/command/testdata/backend-plan-legacy-data/main.tf similarity index 100% rename from internal/command/testdata/backend-plan-legacy-data/main.tf rename to command/testdata/backend-plan-legacy-data/main.tf diff --git a/internal/command/testdata/backend-plan-legacy-data/state.tfstate b/command/testdata/backend-plan-legacy-data/state.tfstate similarity index 100% rename from internal/command/testdata/backend-plan-legacy-data/state.tfstate rename to command/testdata/backend-plan-legacy-data/state.tfstate diff --git a/internal/command/testdata/backend-plan-legacy/readme.txt b/command/testdata/backend-plan-legacy/readme.txt similarity index 100% rename from internal/command/testdata/backend-plan-legacy/readme.txt rename to command/testdata/backend-plan-legacy/readme.txt diff --git a/internal/command/testdata/backend-plan-local-match/main.tf b/command/testdata/backend-plan-local-match/main.tf similarity index 100% rename from internal/command/testdata/backend-plan-local-match/main.tf rename to command/testdata/backend-plan-local-match/main.tf diff --git a/internal/command/testdata/backend-plan-local-match/terraform.tfstate b/command/testdata/backend-plan-local-match/terraform.tfstate similarity index 100% rename from internal/command/testdata/backend-plan-local-match/terraform.tfstate rename to command/testdata/backend-plan-local-match/terraform.tfstate diff --git a/internal/command/testdata/backend-plan-local-mismatch-lineage/main.tf b/command/testdata/backend-plan-local-mismatch-lineage/main.tf similarity index 100% rename from internal/command/testdata/backend-plan-local-mismatch-lineage/main.tf rename to command/testdata/backend-plan-local-mismatch-lineage/main.tf diff --git a/internal/command/testdata/backend-plan-local-mismatch-lineage/terraform.tfstate b/command/testdata/backend-plan-local-mismatch-lineage/terraform.tfstate similarity index 100% rename from internal/command/testdata/backend-plan-local-mismatch-lineage/terraform.tfstate rename to command/testdata/backend-plan-local-mismatch-lineage/terraform.tfstate diff --git a/internal/command/testdata/backend-plan-local-newer/main.tf b/command/testdata/backend-plan-local-newer/main.tf similarity index 100% rename from internal/command/testdata/backend-plan-local-newer/main.tf rename to command/testdata/backend-plan-local-newer/main.tf diff --git a/internal/command/testdata/backend-plan-local-newer/terraform.tfstate b/command/testdata/backend-plan-local-newer/terraform.tfstate similarity index 100% rename from internal/command/testdata/backend-plan-local-newer/terraform.tfstate rename to command/testdata/backend-plan-local-newer/terraform.tfstate diff --git a/internal/command/testdata/backend-plan-local/main.tf b/command/testdata/backend-plan-local/main.tf similarity index 100% rename from internal/command/testdata/backend-plan-local/main.tf rename to command/testdata/backend-plan-local/main.tf diff --git a/internal/command/testdata/backend-unchanged-with-legacy/.terraform/terraform.tfstate b/command/testdata/backend-unchanged-with-legacy/.terraform/terraform.tfstate similarity index 100% rename from internal/command/testdata/backend-unchanged-with-legacy/.terraform/terraform.tfstate rename to command/testdata/backend-unchanged-with-legacy/.terraform/terraform.tfstate diff --git a/internal/command/testdata/backend-unchanged-with-legacy/local-state-old.tfstate b/command/testdata/backend-unchanged-with-legacy/local-state-old.tfstate similarity index 100% rename from internal/command/testdata/backend-unchanged-with-legacy/local-state-old.tfstate rename to command/testdata/backend-unchanged-with-legacy/local-state-old.tfstate diff --git a/internal/command/testdata/backend-unchanged-with-legacy/local-state.tfstate b/command/testdata/backend-unchanged-with-legacy/local-state.tfstate similarity index 100% rename from internal/command/testdata/backend-unchanged-with-legacy/local-state.tfstate rename to command/testdata/backend-unchanged-with-legacy/local-state.tfstate diff --git a/internal/command/testdata/backend-unchanged-with-legacy/main.tf b/command/testdata/backend-unchanged-with-legacy/main.tf similarity index 100% rename from internal/command/testdata/backend-unchanged-with-legacy/main.tf rename to command/testdata/backend-unchanged-with-legacy/main.tf diff --git a/internal/command/testdata/backend-unchanged/.terraform/terraform.tfstate b/command/testdata/backend-unchanged/.terraform/terraform.tfstate similarity index 100% rename from internal/command/testdata/backend-unchanged/.terraform/terraform.tfstate rename to command/testdata/backend-unchanged/.terraform/terraform.tfstate diff --git a/internal/command/testdata/backend-unchanged/local-state.tfstate b/command/testdata/backend-unchanged/local-state.tfstate similarity index 100% rename from internal/command/testdata/backend-unchanged/local-state.tfstate rename to command/testdata/backend-unchanged/local-state.tfstate diff --git a/internal/command/testdata/backend-unchanged/main.tf b/command/testdata/backend-unchanged/main.tf similarity index 100% rename from internal/command/testdata/backend-unchanged/main.tf rename to command/testdata/backend-unchanged/main.tf diff --git a/internal/command/testdata/backend-unset-with-legacy/.terraform/terraform.tfstate b/command/testdata/backend-unset-with-legacy/.terraform/terraform.tfstate similarity index 100% rename from internal/command/testdata/backend-unset-with-legacy/.terraform/terraform.tfstate rename to command/testdata/backend-unset-with-legacy/.terraform/terraform.tfstate diff --git a/internal/command/testdata/backend-unset-with-legacy/local-state-old.tfstate b/command/testdata/backend-unset-with-legacy/local-state-old.tfstate similarity index 100% rename from internal/command/testdata/backend-unset-with-legacy/local-state-old.tfstate rename to command/testdata/backend-unset-with-legacy/local-state-old.tfstate diff --git a/internal/command/testdata/backend-unset-with-legacy/local-state.tfstate b/command/testdata/backend-unset-with-legacy/local-state.tfstate similarity index 100% rename from internal/command/testdata/backend-unset-with-legacy/local-state.tfstate rename to command/testdata/backend-unset-with-legacy/local-state.tfstate diff --git a/internal/command/testdata/backend-unset-with-legacy/main.tf b/command/testdata/backend-unset-with-legacy/main.tf similarity index 100% rename from internal/command/testdata/backend-unset-with-legacy/main.tf rename to command/testdata/backend-unset-with-legacy/main.tf diff --git a/internal/command/testdata/backend-unset/.terraform/terraform.tfstate b/command/testdata/backend-unset/.terraform/terraform.tfstate similarity index 100% rename from internal/command/testdata/backend-unset/.terraform/terraform.tfstate rename to command/testdata/backend-unset/.terraform/terraform.tfstate diff --git a/internal/command/testdata/backend-unset/local-state.tfstate b/command/testdata/backend-unset/local-state.tfstate similarity index 100% rename from internal/command/testdata/backend-unset/local-state.tfstate rename to command/testdata/backend-unset/local-state.tfstate diff --git a/internal/command/testdata/backend-unset/main.tf b/command/testdata/backend-unset/main.tf similarity index 100% rename from internal/command/testdata/backend-unset/main.tf rename to command/testdata/backend-unset/main.tf diff --git a/internal/command/testdata/command-check-required-version/main.tf b/command/testdata/command-check-required-version/main.tf similarity index 100% rename from internal/command/testdata/command-check-required-version/main.tf rename to command/testdata/command-check-required-version/main.tf diff --git a/internal/command/testdata/empty-file b/command/testdata/empty-file similarity index 100% rename from internal/command/testdata/empty-file rename to command/testdata/empty-file diff --git a/internal/command/testdata/empty/README b/command/testdata/empty/README similarity index 100% rename from internal/command/testdata/empty/README rename to command/testdata/empty/README diff --git a/internal/command/testdata/fmt/general_in.tf b/command/testdata/fmt/general_in.tf similarity index 100% rename from internal/command/testdata/fmt/general_in.tf rename to command/testdata/fmt/general_in.tf diff --git a/internal/command/testdata/fmt/general_out.tf b/command/testdata/fmt/general_out.tf similarity index 100% rename from internal/command/testdata/fmt/general_out.tf rename to command/testdata/fmt/general_out.tf diff --git a/internal/command/testdata/fmt/variable_type_in.tf b/command/testdata/fmt/variable_type_in.tf similarity index 100% rename from internal/command/testdata/fmt/variable_type_in.tf rename to command/testdata/fmt/variable_type_in.tf diff --git a/internal/command/testdata/fmt/variable_type_out.tf b/command/testdata/fmt/variable_type_out.tf similarity index 100% rename from internal/command/testdata/fmt/variable_type_out.tf rename to command/testdata/fmt/variable_type_out.tf diff --git a/internal/command/testdata/get/foo/main.tf b/command/testdata/get/foo/main.tf similarity index 100% rename from internal/command/testdata/get/foo/main.tf rename to command/testdata/get/foo/main.tf diff --git a/internal/command/testdata/get/main.tf b/command/testdata/get/main.tf similarity index 100% rename from internal/command/testdata/get/main.tf rename to command/testdata/get/main.tf diff --git a/internal/command/testdata/graph/main.tf b/command/testdata/graph/main.tf similarity index 100% rename from internal/command/testdata/graph/main.tf rename to command/testdata/graph/main.tf diff --git a/internal/command/testdata/import-missing-resource-config/main.tf b/command/testdata/import-missing-resource-config/main.tf similarity index 100% rename from internal/command/testdata/import-missing-resource-config/main.tf rename to command/testdata/import-missing-resource-config/main.tf diff --git a/internal/command/testdata/import-module-input-variable/child/main.tf b/command/testdata/import-module-input-variable/child/main.tf similarity index 100% rename from internal/command/testdata/import-module-input-variable/child/main.tf rename to command/testdata/import-module-input-variable/child/main.tf diff --git a/internal/command/testdata/import-module-input-variable/main.tf b/command/testdata/import-module-input-variable/main.tf similarity index 100% rename from internal/command/testdata/import-module-input-variable/main.tf rename to command/testdata/import-module-input-variable/main.tf diff --git a/internal/command/testdata/import-module-input-variable/terraform.tfvars b/command/testdata/import-module-input-variable/terraform.tfvars similarity index 100% rename from internal/command/testdata/import-module-input-variable/terraform.tfvars rename to command/testdata/import-module-input-variable/terraform.tfvars diff --git a/internal/command/testdata/import-module-var-file/child/main.tf b/command/testdata/import-module-var-file/child/main.tf similarity index 100% rename from internal/command/testdata/import-module-var-file/child/main.tf rename to command/testdata/import-module-var-file/child/main.tf diff --git a/internal/command/testdata/import-module-var-file/main.tf b/command/testdata/import-module-var-file/main.tf similarity index 100% rename from internal/command/testdata/import-module-var-file/main.tf rename to command/testdata/import-module-var-file/main.tf diff --git a/internal/command/testdata/import-module-var-file/terraform.tfvars b/command/testdata/import-module-var-file/terraform.tfvars similarity index 100% rename from internal/command/testdata/import-module-var-file/terraform.tfvars rename to command/testdata/import-module-var-file/terraform.tfvars diff --git a/internal/command/testdata/import-provider-aliased/main.tf b/command/testdata/import-provider-aliased/main.tf similarity index 100% rename from internal/command/testdata/import-provider-aliased/main.tf rename to command/testdata/import-provider-aliased/main.tf diff --git a/internal/command/testdata/import-provider-datasource/main.tf b/command/testdata/import-provider-datasource/main.tf similarity index 100% rename from internal/command/testdata/import-provider-datasource/main.tf rename to command/testdata/import-provider-datasource/main.tf diff --git a/internal/command/testdata/import-provider-implicit/main.tf b/command/testdata/import-provider-implicit/main.tf similarity index 100% rename from internal/command/testdata/import-provider-implicit/main.tf rename to command/testdata/import-provider-implicit/main.tf diff --git a/internal/command/testdata/import-provider-invalid/main.tf b/command/testdata/import-provider-invalid/main.tf similarity index 100% rename from internal/command/testdata/import-provider-invalid/main.tf rename to command/testdata/import-provider-invalid/main.tf diff --git a/internal/command/testdata/import-provider-remote-state/main.tf b/command/testdata/import-provider-remote-state/main.tf similarity index 100% rename from internal/command/testdata/import-provider-remote-state/main.tf rename to command/testdata/import-provider-remote-state/main.tf diff --git a/internal/command/testdata/import-provider-var-default/main.tf b/command/testdata/import-provider-var-default/main.tf similarity index 100% rename from internal/command/testdata/import-provider-var-default/main.tf rename to command/testdata/import-provider-var-default/main.tf diff --git a/internal/command/testdata/import-provider-var-default/terraform.tfvars b/command/testdata/import-provider-var-default/terraform.tfvars similarity index 100% rename from internal/command/testdata/import-provider-var-default/terraform.tfvars rename to command/testdata/import-provider-var-default/terraform.tfvars diff --git a/internal/command/testdata/import-provider-var-file/blah.tfvars b/command/testdata/import-provider-var-file/blah.tfvars similarity index 100% rename from internal/command/testdata/import-provider-var-file/blah.tfvars rename to command/testdata/import-provider-var-file/blah.tfvars diff --git a/internal/command/testdata/import-provider-var-file/main.tf b/command/testdata/import-provider-var-file/main.tf similarity index 100% rename from internal/command/testdata/import-provider-var-file/main.tf rename to command/testdata/import-provider-var-file/main.tf diff --git a/internal/command/testdata/import-provider-var/main.tf b/command/testdata/import-provider-var/main.tf similarity index 100% rename from internal/command/testdata/import-provider-var/main.tf rename to command/testdata/import-provider-var/main.tf diff --git a/internal/command/testdata/import-provider/main.tf b/command/testdata/import-provider/main.tf similarity index 100% rename from internal/command/testdata/import-provider/main.tf rename to command/testdata/import-provider/main.tf diff --git a/internal/command/testdata/init-backend-config-file-change-migrate-existing/.terraform/terraform.tfstate b/command/testdata/init-backend-config-file-change-migrate-existing/.terraform/terraform.tfstate similarity index 100% rename from internal/command/testdata/init-backend-config-file-change-migrate-existing/.terraform/terraform.tfstate rename to command/testdata/init-backend-config-file-change-migrate-existing/.terraform/terraform.tfstate diff --git a/internal/command/testdata/init-backend-config-file-change-migrate-existing/input.config b/command/testdata/init-backend-config-file-change-migrate-existing/input.config similarity index 100% rename from internal/command/testdata/init-backend-config-file-change-migrate-existing/input.config rename to command/testdata/init-backend-config-file-change-migrate-existing/input.config diff --git a/internal/command/testdata/init-backend-config-file-change-migrate-existing/local-state.tfstate b/command/testdata/init-backend-config-file-change-migrate-existing/local-state.tfstate similarity index 100% rename from internal/command/testdata/init-backend-config-file-change-migrate-existing/local-state.tfstate rename to command/testdata/init-backend-config-file-change-migrate-existing/local-state.tfstate diff --git a/internal/command/testdata/init-backend-config-file-change-migrate-existing/main.tf b/command/testdata/init-backend-config-file-change-migrate-existing/main.tf similarity index 100% rename from internal/command/testdata/init-backend-config-file-change-migrate-existing/main.tf rename to command/testdata/init-backend-config-file-change-migrate-existing/main.tf diff --git a/internal/command/testdata/init-backend-config-file-change/.terraform/terraform.tfstate b/command/testdata/init-backend-config-file-change/.terraform/terraform.tfstate similarity index 100% rename from internal/command/testdata/init-backend-config-file-change/.terraform/terraform.tfstate rename to command/testdata/init-backend-config-file-change/.terraform/terraform.tfstate diff --git a/internal/command/testdata/init-backend-config-file-change/input.config b/command/testdata/init-backend-config-file-change/input.config similarity index 100% rename from internal/command/testdata/init-backend-config-file-change/input.config rename to command/testdata/init-backend-config-file-change/input.config diff --git a/internal/command/testdata/init-backend-config-file-change/main.tf b/command/testdata/init-backend-config-file-change/main.tf similarity index 100% rename from internal/command/testdata/init-backend-config-file-change/main.tf rename to command/testdata/init-backend-config-file-change/main.tf diff --git a/internal/command/testdata/init-backend-config-file/backend.config b/command/testdata/init-backend-config-file/backend.config similarity index 100% rename from internal/command/testdata/init-backend-config-file/backend.config rename to command/testdata/init-backend-config-file/backend.config diff --git a/internal/command/testdata/init-backend-config-file/input.config b/command/testdata/init-backend-config-file/input.config similarity index 100% rename from internal/command/testdata/init-backend-config-file/input.config rename to command/testdata/init-backend-config-file/input.config diff --git a/internal/command/testdata/init-backend-config-file/invalid.config b/command/testdata/init-backend-config-file/invalid.config similarity index 100% rename from internal/command/testdata/init-backend-config-file/invalid.config rename to command/testdata/init-backend-config-file/invalid.config diff --git a/internal/command/testdata/init-backend-config-file/main.tf b/command/testdata/init-backend-config-file/main.tf similarity index 100% rename from internal/command/testdata/init-backend-config-file/main.tf rename to command/testdata/init-backend-config-file/main.tf diff --git a/internal/command/testdata/init-backend-config-kv/main.tf b/command/testdata/init-backend-config-kv/main.tf similarity index 100% rename from internal/command/testdata/init-backend-config-kv/main.tf rename to command/testdata/init-backend-config-kv/main.tf diff --git a/internal/command/testdata/init-backend-empty/main.tf b/command/testdata/init-backend-empty/main.tf similarity index 100% rename from internal/command/testdata/init-backend-empty/main.tf rename to command/testdata/init-backend-empty/main.tf diff --git a/internal/command/testdata/init-backend-http/main.tf b/command/testdata/init-backend-http/main.tf similarity index 100% rename from internal/command/testdata/init-backend-http/main.tf rename to command/testdata/init-backend-http/main.tf diff --git a/internal/command/testdata/init-backend-migrate-while-locked/.terraform/terraform.tfstate b/command/testdata/init-backend-migrate-while-locked/.terraform/terraform.tfstate similarity index 100% rename from internal/command/testdata/init-backend-migrate-while-locked/.terraform/terraform.tfstate rename to command/testdata/init-backend-migrate-while-locked/.terraform/terraform.tfstate diff --git a/internal/command/testdata/init-backend-migrate-while-locked/input.config b/command/testdata/init-backend-migrate-while-locked/input.config similarity index 100% rename from internal/command/testdata/init-backend-migrate-while-locked/input.config rename to command/testdata/init-backend-migrate-while-locked/input.config diff --git a/internal/command/testdata/init-backend-migrate-while-locked/main.tf b/command/testdata/init-backend-migrate-while-locked/main.tf similarity index 100% rename from internal/command/testdata/init-backend-migrate-while-locked/main.tf rename to command/testdata/init-backend-migrate-while-locked/main.tf diff --git a/internal/command/testdata/init-backend-selected-workspace-doesnt-exist-multi/.terraform/environment b/command/testdata/init-backend-selected-workspace-doesnt-exist-multi/.terraform/environment similarity index 100% rename from internal/command/testdata/init-backend-selected-workspace-doesnt-exist-multi/.terraform/environment rename to command/testdata/init-backend-selected-workspace-doesnt-exist-multi/.terraform/environment diff --git a/internal/command/testdata/init-backend-selected-workspace-doesnt-exist-multi/.terraform/terraform.tfstate b/command/testdata/init-backend-selected-workspace-doesnt-exist-multi/.terraform/terraform.tfstate similarity index 100% rename from internal/command/testdata/init-backend-selected-workspace-doesnt-exist-multi/.terraform/terraform.tfstate rename to command/testdata/init-backend-selected-workspace-doesnt-exist-multi/.terraform/terraform.tfstate diff --git a/internal/command/testdata/init-backend-selected-workspace-doesnt-exist-multi/main.tf b/command/testdata/init-backend-selected-workspace-doesnt-exist-multi/main.tf similarity index 100% rename from internal/command/testdata/init-backend-selected-workspace-doesnt-exist-multi/main.tf rename to command/testdata/init-backend-selected-workspace-doesnt-exist-multi/main.tf diff --git a/internal/command/testdata/init-backend-selected-workspace-doesnt-exist-multi/terraform.tfstate b/command/testdata/init-backend-selected-workspace-doesnt-exist-multi/terraform.tfstate similarity index 100% rename from internal/command/testdata/init-backend-selected-workspace-doesnt-exist-multi/terraform.tfstate rename to command/testdata/init-backend-selected-workspace-doesnt-exist-multi/terraform.tfstate diff --git a/internal/command/testdata/init-backend-selected-workspace-doesnt-exist-multi/terraform.tfstate.d/foo/terraform.tfstate b/command/testdata/init-backend-selected-workspace-doesnt-exist-multi/terraform.tfstate.d/foo/terraform.tfstate similarity index 100% rename from internal/command/testdata/init-backend-selected-workspace-doesnt-exist-multi/terraform.tfstate.d/foo/terraform.tfstate rename to command/testdata/init-backend-selected-workspace-doesnt-exist-multi/terraform.tfstate.d/foo/terraform.tfstate diff --git a/internal/command/testdata/init-backend-selected-workspace-doesnt-exist-single/.terraform/environment b/command/testdata/init-backend-selected-workspace-doesnt-exist-single/.terraform/environment similarity index 100% rename from internal/command/testdata/init-backend-selected-workspace-doesnt-exist-single/.terraform/environment rename to command/testdata/init-backend-selected-workspace-doesnt-exist-single/.terraform/environment diff --git a/internal/command/testdata/init-backend-selected-workspace-doesnt-exist-single/.terraform/terraform.tfstate b/command/testdata/init-backend-selected-workspace-doesnt-exist-single/.terraform/terraform.tfstate similarity index 100% rename from internal/command/testdata/init-backend-selected-workspace-doesnt-exist-single/.terraform/terraform.tfstate rename to command/testdata/init-backend-selected-workspace-doesnt-exist-single/.terraform/terraform.tfstate diff --git a/internal/command/testdata/init-backend-selected-workspace-doesnt-exist-single/main.tf b/command/testdata/init-backend-selected-workspace-doesnt-exist-single/main.tf similarity index 100% rename from internal/command/testdata/init-backend-selected-workspace-doesnt-exist-single/main.tf rename to command/testdata/init-backend-selected-workspace-doesnt-exist-single/main.tf diff --git a/internal/command/testdata/init-backend/main.tf b/command/testdata/init-backend/main.tf similarity index 100% rename from internal/command/testdata/init-backend/main.tf rename to command/testdata/init-backend/main.tf diff --git a/internal/command/testdata/init-check-required-version-first-module/main.tf b/command/testdata/init-check-required-version-first-module/main.tf similarity index 100% rename from internal/command/testdata/init-check-required-version-first-module/main.tf rename to command/testdata/init-check-required-version-first-module/main.tf diff --git a/internal/command/testdata/init-check-required-version-first-module/mod/main.tf b/command/testdata/init-check-required-version-first-module/mod/main.tf similarity index 100% rename from internal/command/testdata/init-check-required-version-first-module/mod/main.tf rename to command/testdata/init-check-required-version-first-module/mod/main.tf diff --git a/internal/command/testdata/init-check-required-version-first/main.tf b/command/testdata/init-check-required-version-first/main.tf similarity index 100% rename from internal/command/testdata/init-check-required-version-first/main.tf rename to command/testdata/init-check-required-version-first/main.tf diff --git a/internal/command/testdata/init-check-required-version/main.tf b/command/testdata/init-check-required-version/main.tf similarity index 100% rename from internal/command/testdata/init-check-required-version/main.tf rename to command/testdata/init-check-required-version/main.tf diff --git a/internal/command/testdata/init-cloud-simple/init-cloud-simple.tf b/command/testdata/init-cloud-simple/init-cloud-simple.tf similarity index 100% rename from internal/command/testdata/init-cloud-simple/init-cloud-simple.tf rename to command/testdata/init-cloud-simple/init-cloud-simple.tf diff --git a/internal/command/testdata/init-get-provider-detected-legacy/.terraform/modules/dicerolls/terraform-random-bar-1.0.0/main.tf b/command/testdata/init-get-provider-detected-legacy/.terraform/modules/dicerolls/terraform-random-bar-1.0.0/main.tf similarity index 100% rename from internal/command/testdata/init-get-provider-detected-legacy/.terraform/modules/dicerolls/terraform-random-bar-1.0.0/main.tf rename to command/testdata/init-get-provider-detected-legacy/.terraform/modules/dicerolls/terraform-random-bar-1.0.0/main.tf diff --git a/internal/command/testdata/init-get-provider-detected-legacy/.terraform/modules/modules.json b/command/testdata/init-get-provider-detected-legacy/.terraform/modules/modules.json similarity index 100% rename from internal/command/testdata/init-get-provider-detected-legacy/.terraform/modules/modules.json rename to command/testdata/init-get-provider-detected-legacy/.terraform/modules/modules.json diff --git a/internal/command/testdata/init-get-provider-detected-legacy/child/main.tf b/command/testdata/init-get-provider-detected-legacy/child/main.tf similarity index 100% rename from internal/command/testdata/init-get-provider-detected-legacy/child/main.tf rename to command/testdata/init-get-provider-detected-legacy/child/main.tf diff --git a/internal/command/testdata/init-get-provider-detected-legacy/main.tf b/command/testdata/init-get-provider-detected-legacy/main.tf similarity index 100% rename from internal/command/testdata/init-get-provider-detected-legacy/main.tf rename to command/testdata/init-get-provider-detected-legacy/main.tf diff --git a/internal/command/testdata/init-get-provider-invalid-package/main.tf b/command/testdata/init-get-provider-invalid-package/main.tf similarity index 100% rename from internal/command/testdata/init-get-provider-invalid-package/main.tf rename to command/testdata/init-get-provider-invalid-package/main.tf diff --git a/internal/command/testdata/init-get-provider-legacy-from-state/main.tf b/command/testdata/init-get-provider-legacy-from-state/main.tf similarity index 100% rename from internal/command/testdata/init-get-provider-legacy-from-state/main.tf rename to command/testdata/init-get-provider-legacy-from-state/main.tf diff --git a/internal/command/testdata/init-get-provider-legacy-from-state/terraform.tfstate b/command/testdata/init-get-provider-legacy-from-state/terraform.tfstate similarity index 100% rename from internal/command/testdata/init-get-provider-legacy-from-state/terraform.tfstate rename to command/testdata/init-get-provider-legacy-from-state/terraform.tfstate diff --git a/internal/command/testdata/init-get-provider-source/main.tf b/command/testdata/init-get-provider-source/main.tf similarity index 100% rename from internal/command/testdata/init-get-provider-source/main.tf rename to command/testdata/init-get-provider-source/main.tf diff --git a/internal/command/testdata/init-get-providers/main.tf b/command/testdata/init-get-providers/main.tf similarity index 100% rename from internal/command/testdata/init-get-providers/main.tf rename to command/testdata/init-get-providers/main.tf diff --git a/internal/command/testdata/init-get/foo/main.tf b/command/testdata/init-get/foo/main.tf similarity index 100% rename from internal/command/testdata/init-get/foo/main.tf rename to command/testdata/init-get/foo/main.tf diff --git a/internal/command/testdata/init-get/main.tf b/command/testdata/init-get/main.tf similarity index 100% rename from internal/command/testdata/init-get/main.tf rename to command/testdata/init-get/main.tf diff --git a/internal/command/testdata/init-internal-invalid/main.tf b/command/testdata/init-internal-invalid/main.tf similarity index 100% rename from internal/command/testdata/init-internal-invalid/main.tf rename to command/testdata/init-internal-invalid/main.tf diff --git a/internal/command/testdata/init-internal/main.tf b/command/testdata/init-internal/main.tf similarity index 100% rename from internal/command/testdata/init-internal/main.tf rename to command/testdata/init-internal/main.tf diff --git a/internal/command/testdata/init-legacy-provider-cache/.terraform/plugins/example.com/test/b/1.1.0/os_arch/terraform-provider-b b/command/testdata/init-legacy-provider-cache/.terraform/plugins/example.com/test/b/1.1.0/os_arch/terraform-provider-b similarity index 100% rename from internal/command/testdata/init-legacy-provider-cache/.terraform/plugins/example.com/test/b/1.1.0/os_arch/terraform-provider-b rename to command/testdata/init-legacy-provider-cache/.terraform/plugins/example.com/test/b/1.1.0/os_arch/terraform-provider-b diff --git a/internal/command/testdata/init-legacy-provider-cache/.terraform/plugins/registry.terraform.io/hashicorp/c/2.0.0/os_arch/terraform-provider-c b/command/testdata/init-legacy-provider-cache/.terraform/plugins/registry.terraform.io/hashicorp/c/2.0.0/os_arch/terraform-provider-c similarity index 100% rename from internal/command/testdata/init-legacy-provider-cache/.terraform/plugins/registry.terraform.io/hashicorp/c/2.0.0/os_arch/terraform-provider-c rename to command/testdata/init-legacy-provider-cache/.terraform/plugins/registry.terraform.io/hashicorp/c/2.0.0/os_arch/terraform-provider-c diff --git a/internal/command/testdata/init-legacy-provider-cache/versions.tf b/command/testdata/init-legacy-provider-cache/versions.tf similarity index 100% rename from internal/command/testdata/init-legacy-provider-cache/versions.tf rename to command/testdata/init-legacy-provider-cache/versions.tf diff --git a/internal/command/testdata/init-legacy-rc/main.tf b/command/testdata/init-legacy-rc/main.tf similarity index 100% rename from internal/command/testdata/init-legacy-rc/main.tf rename to command/testdata/init-legacy-rc/main.tf diff --git a/internal/command/testdata/init-provider-lock-file-readonly-add/main.tf b/command/testdata/init-provider-lock-file-readonly-add/main.tf similarity index 100% rename from internal/command/testdata/init-provider-lock-file-readonly-add/main.tf rename to command/testdata/init-provider-lock-file-readonly-add/main.tf diff --git a/internal/command/testdata/init-provider-lock-file/main.tf b/command/testdata/init-provider-lock-file/main.tf similarity index 100% rename from internal/command/testdata/init-provider-lock-file/main.tf rename to command/testdata/init-provider-lock-file/main.tf diff --git a/internal/command/testdata/init-provider-now-unused/main.tf b/command/testdata/init-provider-now-unused/main.tf similarity index 100% rename from internal/command/testdata/init-provider-now-unused/main.tf rename to command/testdata/init-provider-now-unused/main.tf diff --git a/internal/command/testdata/init-providers-lock/main.tf b/command/testdata/init-providers-lock/main.tf similarity index 100% rename from internal/command/testdata/init-providers-lock/main.tf rename to command/testdata/init-providers-lock/main.tf diff --git a/internal/command/testdata/init-registry-module/main.tf b/command/testdata/init-registry-module/main.tf similarity index 100% rename from internal/command/testdata/init-registry-module/main.tf rename to command/testdata/init-registry-module/main.tf diff --git a/internal/command/testdata/init-required-providers/main.tf b/command/testdata/init-required-providers/main.tf similarity index 100% rename from internal/command/testdata/init-required-providers/main.tf rename to command/testdata/init-required-providers/main.tf diff --git a/internal/command/testdata/init-syntax-invalid-backend-invalid/main.tf b/command/testdata/init-syntax-invalid-backend-invalid/main.tf similarity index 100% rename from internal/command/testdata/init-syntax-invalid-backend-invalid/main.tf rename to command/testdata/init-syntax-invalid-backend-invalid/main.tf diff --git a/internal/command/testdata/init-syntax-invalid-no-backend/main.tf b/command/testdata/init-syntax-invalid-no-backend/main.tf similarity index 100% rename from internal/command/testdata/init-syntax-invalid-no-backend/main.tf rename to command/testdata/init-syntax-invalid-no-backend/main.tf diff --git a/internal/command/testdata/init-syntax-invalid-with-backend/main.tf b/command/testdata/init-syntax-invalid-with-backend/main.tf similarity index 100% rename from internal/command/testdata/init-syntax-invalid-with-backend/main.tf rename to command/testdata/init-syntax-invalid-with-backend/main.tf diff --git a/internal/command/testdata/init/hello.tf b/command/testdata/init/hello.tf similarity index 100% rename from internal/command/testdata/init/hello.tf rename to command/testdata/init/hello.tf diff --git a/internal/command/testdata/inmem-backend/main.tf b/command/testdata/inmem-backend/main.tf similarity index 100% rename from internal/command/testdata/inmem-backend/main.tf rename to command/testdata/inmem-backend/main.tf diff --git a/internal/command/testdata/login-oauth-server/main.go b/command/testdata/login-oauth-server/main.go similarity index 88% rename from internal/command/testdata/login-oauth-server/main.go rename to command/testdata/login-oauth-server/main.go index 105936c4f8e6..6fd4ef2759df 100644 --- a/internal/command/testdata/login-oauth-server/main.go +++ b/command/testdata/login-oauth-server/main.go @@ -10,7 +10,7 @@ // This is _not_ the main way to use this oauthserver package. For automated // test code, import it as a normal Go package instead: // -// import oauthserver "github.com/hashicorp/terraform/internal/command/testdata/login-oauth-server" +// import oauthserver "github.com/hashicorp/terraform/command/testdata/login-oauth-server" package main @@ -20,7 +20,7 @@ import ( "net/http" "os" - oauthserver "github.com/hashicorp/terraform/internal/command/testdata/login-oauth-server" + oauthserver "github.com/hashicorp/terraform/command/testdata/login-oauth-server" ) func main() { diff --git a/internal/command/testdata/login-oauth-server/oauthserver.go b/command/testdata/login-oauth-server/oauthserver.go similarity index 100% rename from internal/command/testdata/login-oauth-server/oauthserver.go rename to command/testdata/login-oauth-server/oauthserver.go diff --git a/internal/command/testdata/login-tfe-server/tfeserver.go b/command/testdata/login-tfe-server/tfeserver.go similarity index 100% rename from internal/command/testdata/login-tfe-server/tfeserver.go rename to command/testdata/login-tfe-server/tfeserver.go diff --git a/internal/command/testdata/modules/.terraform/modules/modules.json b/command/testdata/modules/.terraform/modules/modules.json similarity index 100% rename from internal/command/testdata/modules/.terraform/modules/modules.json rename to command/testdata/modules/.terraform/modules/modules.json diff --git a/internal/command/testdata/modules/child/main.tf b/command/testdata/modules/child/main.tf similarity index 100% rename from internal/command/testdata/modules/child/main.tf rename to command/testdata/modules/child/main.tf diff --git a/internal/command/testdata/modules/main.tf b/command/testdata/modules/main.tf similarity index 100% rename from internal/command/testdata/modules/main.tf rename to command/testdata/modules/main.tf diff --git a/internal/command/testdata/modules/terraform.tfstate b/command/testdata/modules/terraform.tfstate similarity index 100% rename from internal/command/testdata/modules/terraform.tfstate rename to command/testdata/modules/terraform.tfstate diff --git a/internal/command/testdata/parallelism/main.tf b/command/testdata/parallelism/main.tf similarity index 100% rename from internal/command/testdata/parallelism/main.tf rename to command/testdata/parallelism/main.tf diff --git a/internal/command/testdata/plan-emptydiff/main.tf b/command/testdata/plan-emptydiff/main.tf similarity index 100% rename from internal/command/testdata/plan-emptydiff/main.tf rename to command/testdata/plan-emptydiff/main.tf diff --git a/internal/command/testdata/plan-fail-condition/main.tf b/command/testdata/plan-fail-condition/main.tf similarity index 100% rename from internal/command/testdata/plan-fail-condition/main.tf rename to command/testdata/plan-fail-condition/main.tf diff --git a/internal/command/testdata/plan-invalid/main.tf b/command/testdata/plan-invalid/main.tf similarity index 100% rename from internal/command/testdata/plan-invalid/main.tf rename to command/testdata/plan-invalid/main.tf diff --git a/internal/command/testdata/plan-out-backend-legacy/main.tf b/command/testdata/plan-out-backend-legacy/main.tf similarity index 100% rename from internal/command/testdata/plan-out-backend-legacy/main.tf rename to command/testdata/plan-out-backend-legacy/main.tf diff --git a/internal/command/testdata/plan-out-backend/main.tf b/command/testdata/plan-out-backend/main.tf similarity index 100% rename from internal/command/testdata/plan-out-backend/main.tf rename to command/testdata/plan-out-backend/main.tf diff --git a/internal/command/testdata/plan-provider-input/main.tf b/command/testdata/plan-provider-input/main.tf similarity index 100% rename from internal/command/testdata/plan-provider-input/main.tf rename to command/testdata/plan-provider-input/main.tf diff --git a/internal/command/testdata/plan-replace/main.tf b/command/testdata/plan-replace/main.tf similarity index 100% rename from internal/command/testdata/plan-replace/main.tf rename to command/testdata/plan-replace/main.tf diff --git a/internal/command/testdata/plan-vars/main.tf b/command/testdata/plan-vars/main.tf similarity index 100% rename from internal/command/testdata/plan-vars/main.tf rename to command/testdata/plan-vars/main.tf diff --git a/internal/command/testdata/plan/main.tf b/command/testdata/plan/main.tf similarity index 100% rename from internal/command/testdata/plan/main.tf rename to command/testdata/plan/main.tf diff --git a/internal/command/testdata/plan/output.jsonlog b/command/testdata/plan/output.jsonlog similarity index 100% rename from internal/command/testdata/plan/output.jsonlog rename to command/testdata/plan/output.jsonlog diff --git a/internal/command/testdata/providers-lock/append/.terraform.lock.hcl b/command/testdata/providers-lock/append/.terraform.lock.hcl similarity index 100% rename from internal/command/testdata/providers-lock/append/.terraform.lock.hcl rename to command/testdata/providers-lock/append/.terraform.lock.hcl diff --git a/internal/command/testdata/providers-lock/append/fs-mirror/registry.terraform.io/hashicorp/test/1.0.0/os_arch/terraform-provider-test b/command/testdata/providers-lock/append/fs-mirror/registry.terraform.io/hashicorp/test/1.0.0/os_arch/terraform-provider-test similarity index 100% rename from internal/command/testdata/providers-lock/append/fs-mirror/registry.terraform.io/hashicorp/test/1.0.0/os_arch/terraform-provider-test rename to command/testdata/providers-lock/append/fs-mirror/registry.terraform.io/hashicorp/test/1.0.0/os_arch/terraform-provider-test diff --git a/internal/command/testdata/providers-lock/append/main.tf b/command/testdata/providers-lock/append/main.tf similarity index 100% rename from internal/command/testdata/providers-lock/append/main.tf rename to command/testdata/providers-lock/append/main.tf diff --git a/internal/command/testdata/providers-lock/basic/fs-mirror/registry.terraform.io/hashicorp/test/1.0.0/os_arch/terraform-provider-test b/command/testdata/providers-lock/basic/fs-mirror/registry.terraform.io/hashicorp/test/1.0.0/os_arch/terraform-provider-test similarity index 100% rename from internal/command/testdata/providers-lock/basic/fs-mirror/registry.terraform.io/hashicorp/test/1.0.0/os_arch/terraform-provider-test rename to command/testdata/providers-lock/basic/fs-mirror/registry.terraform.io/hashicorp/test/1.0.0/os_arch/terraform-provider-test diff --git a/internal/command/testdata/providers-lock/basic/main.tf b/command/testdata/providers-lock/basic/main.tf similarity index 100% rename from internal/command/testdata/providers-lock/basic/main.tf rename to command/testdata/providers-lock/basic/main.tf diff --git a/internal/command/testdata/providers-schema/basic/output.json b/command/testdata/providers-schema/basic/output.json similarity index 100% rename from internal/command/testdata/providers-schema/basic/output.json rename to command/testdata/providers-schema/basic/output.json diff --git a/internal/command/testdata/providers-schema/basic/provider.tf b/command/testdata/providers-schema/basic/provider.tf similarity index 100% rename from internal/command/testdata/providers-schema/basic/provider.tf rename to command/testdata/providers-schema/basic/provider.tf diff --git a/internal/command/testdata/providers-schema/empty/main.tf b/command/testdata/providers-schema/empty/main.tf similarity index 100% rename from internal/command/testdata/providers-schema/empty/main.tf rename to command/testdata/providers-schema/empty/main.tf diff --git a/internal/command/testdata/providers-schema/empty/output.json b/command/testdata/providers-schema/empty/output.json similarity index 100% rename from internal/command/testdata/providers-schema/empty/output.json rename to command/testdata/providers-schema/empty/output.json diff --git a/internal/command/testdata/providers-schema/required/output.json b/command/testdata/providers-schema/required/output.json similarity index 100% rename from internal/command/testdata/providers-schema/required/output.json rename to command/testdata/providers-schema/required/output.json diff --git a/internal/command/testdata/providers-schema/required/provider.tf b/command/testdata/providers-schema/required/provider.tf similarity index 100% rename from internal/command/testdata/providers-schema/required/provider.tf rename to command/testdata/providers-schema/required/provider.tf diff --git a/internal/command/testdata/providers/basic/main.tf b/command/testdata/providers/basic/main.tf similarity index 100% rename from internal/command/testdata/providers/basic/main.tf rename to command/testdata/providers/basic/main.tf diff --git a/internal/command/testdata/providers/modules/child/main.tf b/command/testdata/providers/modules/child/main.tf similarity index 100% rename from internal/command/testdata/providers/modules/child/main.tf rename to command/testdata/providers/modules/child/main.tf diff --git a/internal/command/testdata/providers/modules/main.tf b/command/testdata/providers/modules/main.tf similarity index 100% rename from internal/command/testdata/providers/modules/main.tf rename to command/testdata/providers/modules/main.tf diff --git a/internal/command/testdata/providers/state/main.tf b/command/testdata/providers/state/main.tf similarity index 100% rename from internal/command/testdata/providers/state/main.tf rename to command/testdata/providers/state/main.tf diff --git a/internal/command/testdata/providers/state/terraform.tfstate b/command/testdata/providers/state/terraform.tfstate similarity index 100% rename from internal/command/testdata/providers/state/terraform.tfstate rename to command/testdata/providers/state/terraform.tfstate diff --git a/internal/command/testdata/push-backend-new/main.tf b/command/testdata/push-backend-new/main.tf similarity index 100% rename from internal/command/testdata/push-backend-new/main.tf rename to command/testdata/push-backend-new/main.tf diff --git a/internal/command/testdata/push-input-partial/main.tf b/command/testdata/push-input-partial/main.tf similarity index 100% rename from internal/command/testdata/push-input-partial/main.tf rename to command/testdata/push-input-partial/main.tf diff --git a/internal/command/testdata/push-input/main.tf b/command/testdata/push-input/main.tf similarity index 100% rename from internal/command/testdata/push-input/main.tf rename to command/testdata/push-input/main.tf diff --git a/internal/command/testdata/push-no-remote/main.tf b/command/testdata/push-no-remote/main.tf similarity index 100% rename from internal/command/testdata/push-no-remote/main.tf rename to command/testdata/push-no-remote/main.tf diff --git a/internal/command/testdata/push-no-upload/child/main.tf b/command/testdata/push-no-upload/child/main.tf similarity index 100% rename from internal/command/testdata/push-no-upload/child/main.tf rename to command/testdata/push-no-upload/child/main.tf diff --git a/internal/command/testdata/push-no-upload/main.tf b/command/testdata/push-no-upload/main.tf similarity index 100% rename from internal/command/testdata/push-no-upload/main.tf rename to command/testdata/push-no-upload/main.tf diff --git a/internal/command/testdata/push-tfvars/main.tf b/command/testdata/push-tfvars/main.tf similarity index 100% rename from internal/command/testdata/push-tfvars/main.tf rename to command/testdata/push-tfvars/main.tf diff --git a/internal/command/testdata/push-tfvars/terraform.tfvars b/command/testdata/push-tfvars/terraform.tfvars similarity index 100% rename from internal/command/testdata/push-tfvars/terraform.tfvars rename to command/testdata/push-tfvars/terraform.tfvars diff --git a/internal/command/testdata/push/main.tf b/command/testdata/push/main.tf similarity index 100% rename from internal/command/testdata/push/main.tf rename to command/testdata/push/main.tf diff --git a/internal/command/testdata/refresh-empty/main.tf b/command/testdata/refresh-empty/main.tf similarity index 100% rename from internal/command/testdata/refresh-empty/main.tf rename to command/testdata/refresh-empty/main.tf diff --git a/internal/command/testdata/refresh-output/main.tf b/command/testdata/refresh-output/main.tf similarity index 100% rename from internal/command/testdata/refresh-output/main.tf rename to command/testdata/refresh-output/main.tf diff --git a/internal/command/testdata/refresh-targeted/main.tf b/command/testdata/refresh-targeted/main.tf similarity index 100% rename from internal/command/testdata/refresh-targeted/main.tf rename to command/testdata/refresh-targeted/main.tf diff --git a/internal/command/testdata/refresh-unset-var/main.tf b/command/testdata/refresh-unset-var/main.tf similarity index 100% rename from internal/command/testdata/refresh-unset-var/main.tf rename to command/testdata/refresh-unset-var/main.tf diff --git a/internal/command/testdata/refresh-var/main.tf b/command/testdata/refresh-var/main.tf similarity index 100% rename from internal/command/testdata/refresh-var/main.tf rename to command/testdata/refresh-var/main.tf diff --git a/internal/command/testdata/refresh/main.tf b/command/testdata/refresh/main.tf similarity index 100% rename from internal/command/testdata/refresh/main.tf rename to command/testdata/refresh/main.tf diff --git a/internal/command/testdata/show-corrupt-statefile/terraform.tfstate b/command/testdata/show-corrupt-statefile/terraform.tfstate similarity index 100% rename from internal/command/testdata/show-corrupt-statefile/terraform.tfstate rename to command/testdata/show-corrupt-statefile/terraform.tfstate diff --git a/internal/command/testdata/show-json-sensitive/main.tf b/command/testdata/show-json-sensitive/main.tf similarity index 100% rename from internal/command/testdata/show-json-sensitive/main.tf rename to command/testdata/show-json-sensitive/main.tf diff --git a/internal/command/testdata/show-json-sensitive/output.json b/command/testdata/show-json-sensitive/output.json similarity index 100% rename from internal/command/testdata/show-json-sensitive/output.json rename to command/testdata/show-json-sensitive/output.json diff --git a/internal/command/testdata/show-json-state/basic/output.json b/command/testdata/show-json-state/basic/output.json similarity index 100% rename from internal/command/testdata/show-json-state/basic/output.json rename to command/testdata/show-json-state/basic/output.json diff --git a/internal/command/testdata/show-json-state/basic/terraform.tfstate b/command/testdata/show-json-state/basic/terraform.tfstate similarity index 100% rename from internal/command/testdata/show-json-state/basic/terraform.tfstate rename to command/testdata/show-json-state/basic/terraform.tfstate diff --git a/internal/command/testdata/show-json-state/empty/output.json b/command/testdata/show-json-state/empty/output.json similarity index 100% rename from internal/command/testdata/show-json-state/empty/output.json rename to command/testdata/show-json-state/empty/output.json diff --git a/internal/command/testdata/show-json-state/empty/terraform.tfstate b/command/testdata/show-json-state/empty/terraform.tfstate similarity index 100% rename from internal/command/testdata/show-json-state/empty/terraform.tfstate rename to command/testdata/show-json-state/empty/terraform.tfstate diff --git a/internal/command/testdata/show-json-state/modules/bar/main.tf b/command/testdata/show-json-state/modules/bar/main.tf similarity index 100% rename from internal/command/testdata/show-json-state/modules/bar/main.tf rename to command/testdata/show-json-state/modules/bar/main.tf diff --git a/internal/command/testdata/show-json-state/modules/foo/main.tf b/command/testdata/show-json-state/modules/foo/main.tf similarity index 100% rename from internal/command/testdata/show-json-state/modules/foo/main.tf rename to command/testdata/show-json-state/modules/foo/main.tf diff --git a/internal/command/testdata/show-json-state/modules/main.tf b/command/testdata/show-json-state/modules/main.tf similarity index 100% rename from internal/command/testdata/show-json-state/modules/main.tf rename to command/testdata/show-json-state/modules/main.tf diff --git a/internal/command/testdata/show-json-state/modules/output.json b/command/testdata/show-json-state/modules/output.json similarity index 100% rename from internal/command/testdata/show-json-state/modules/output.json rename to command/testdata/show-json-state/modules/output.json diff --git a/internal/command/testdata/show-json-state/modules/terraform.tfstate b/command/testdata/show-json-state/modules/terraform.tfstate similarity index 100% rename from internal/command/testdata/show-json-state/modules/terraform.tfstate rename to command/testdata/show-json-state/modules/terraform.tfstate diff --git a/internal/command/testdata/show-json-state/no-state/output.json b/command/testdata/show-json-state/no-state/output.json similarity index 100% rename from internal/command/testdata/show-json-state/no-state/output.json rename to command/testdata/show-json-state/no-state/output.json diff --git a/internal/command/testdata/show-json-state/sensitive-variables/output.json b/command/testdata/show-json-state/sensitive-variables/output.json similarity index 100% rename from internal/command/testdata/show-json-state/sensitive-variables/output.json rename to command/testdata/show-json-state/sensitive-variables/output.json diff --git a/internal/command/testdata/show-json-state/sensitive-variables/terraform.tfstate b/command/testdata/show-json-state/sensitive-variables/terraform.tfstate similarity index 100% rename from internal/command/testdata/show-json-state/sensitive-variables/terraform.tfstate rename to command/testdata/show-json-state/sensitive-variables/terraform.tfstate diff --git a/internal/command/testdata/show-json/basic-create/main.tf b/command/testdata/show-json/basic-create/main.tf similarity index 100% rename from internal/command/testdata/show-json/basic-create/main.tf rename to command/testdata/show-json/basic-create/main.tf diff --git a/internal/command/testdata/show-json/basic-create/output.json b/command/testdata/show-json/basic-create/output.json similarity index 100% rename from internal/command/testdata/show-json/basic-create/output.json rename to command/testdata/show-json/basic-create/output.json diff --git a/internal/command/testdata/show-json/basic-delete/main.tf b/command/testdata/show-json/basic-delete/main.tf similarity index 100% rename from internal/command/testdata/show-json/basic-delete/main.tf rename to command/testdata/show-json/basic-delete/main.tf diff --git a/internal/command/testdata/show-json/basic-delete/output.json b/command/testdata/show-json/basic-delete/output.json similarity index 100% rename from internal/command/testdata/show-json/basic-delete/output.json rename to command/testdata/show-json/basic-delete/output.json diff --git a/internal/command/testdata/show-json/basic-delete/terraform.tfstate b/command/testdata/show-json/basic-delete/terraform.tfstate similarity index 100% rename from internal/command/testdata/show-json/basic-delete/terraform.tfstate rename to command/testdata/show-json/basic-delete/terraform.tfstate diff --git a/internal/command/testdata/show-json/basic-update/main.tf b/command/testdata/show-json/basic-update/main.tf similarity index 100% rename from internal/command/testdata/show-json/basic-update/main.tf rename to command/testdata/show-json/basic-update/main.tf diff --git a/internal/command/testdata/show-json/basic-update/output.json b/command/testdata/show-json/basic-update/output.json similarity index 100% rename from internal/command/testdata/show-json/basic-update/output.json rename to command/testdata/show-json/basic-update/output.json diff --git a/internal/command/testdata/show-json/basic-update/terraform.tfstate b/command/testdata/show-json/basic-update/terraform.tfstate similarity index 100% rename from internal/command/testdata/show-json/basic-update/terraform.tfstate rename to command/testdata/show-json/basic-update/terraform.tfstate diff --git a/internal/command/testdata/show-json/conditions/for-refresh.tfstate b/command/testdata/show-json/conditions/for-refresh.tfstate similarity index 100% rename from internal/command/testdata/show-json/conditions/for-refresh.tfstate rename to command/testdata/show-json/conditions/for-refresh.tfstate diff --git a/internal/command/testdata/show-json/conditions/main.tf b/command/testdata/show-json/conditions/main.tf similarity index 100% rename from internal/command/testdata/show-json/conditions/main.tf rename to command/testdata/show-json/conditions/main.tf diff --git a/internal/command/testdata/show-json/conditions/output-refresh-only.json b/command/testdata/show-json/conditions/output-refresh-only.json similarity index 100% rename from internal/command/testdata/show-json/conditions/output-refresh-only.json rename to command/testdata/show-json/conditions/output-refresh-only.json diff --git a/internal/command/testdata/show-json/conditions/output.json b/command/testdata/show-json/conditions/output.json similarity index 100% rename from internal/command/testdata/show-json/conditions/output.json rename to command/testdata/show-json/conditions/output.json diff --git a/internal/command/testdata/show-json/drift/main.tf b/command/testdata/show-json/drift/main.tf similarity index 100% rename from internal/command/testdata/show-json/drift/main.tf rename to command/testdata/show-json/drift/main.tf diff --git a/internal/command/testdata/show-json/drift/output.json b/command/testdata/show-json/drift/output.json similarity index 100% rename from internal/command/testdata/show-json/drift/output.json rename to command/testdata/show-json/drift/output.json diff --git a/internal/command/testdata/show-json/drift/terraform.tfstate b/command/testdata/show-json/drift/terraform.tfstate similarity index 100% rename from internal/command/testdata/show-json/drift/terraform.tfstate rename to command/testdata/show-json/drift/terraform.tfstate diff --git a/internal/command/testdata/show-json/module-depends-on/foo/main.tf b/command/testdata/show-json/module-depends-on/foo/main.tf similarity index 100% rename from internal/command/testdata/show-json/module-depends-on/foo/main.tf rename to command/testdata/show-json/module-depends-on/foo/main.tf diff --git a/internal/command/testdata/show-json/module-depends-on/main.tf b/command/testdata/show-json/module-depends-on/main.tf similarity index 100% rename from internal/command/testdata/show-json/module-depends-on/main.tf rename to command/testdata/show-json/module-depends-on/main.tf diff --git a/internal/command/testdata/show-json/module-depends-on/output.json b/command/testdata/show-json/module-depends-on/output.json similarity index 100% rename from internal/command/testdata/show-json/module-depends-on/output.json rename to command/testdata/show-json/module-depends-on/output.json diff --git a/internal/command/testdata/show-json/modules/bar/main.tf b/command/testdata/show-json/modules/bar/main.tf similarity index 100% rename from internal/command/testdata/show-json/modules/bar/main.tf rename to command/testdata/show-json/modules/bar/main.tf diff --git a/internal/command/testdata/show-json/modules/foo/main.tf b/command/testdata/show-json/modules/foo/main.tf similarity index 100% rename from internal/command/testdata/show-json/modules/foo/main.tf rename to command/testdata/show-json/modules/foo/main.tf diff --git a/internal/command/testdata/show-json/modules/main.tf b/command/testdata/show-json/modules/main.tf similarity index 100% rename from internal/command/testdata/show-json/modules/main.tf rename to command/testdata/show-json/modules/main.tf diff --git a/internal/command/testdata/show-json/modules/output.json b/command/testdata/show-json/modules/output.json similarity index 100% rename from internal/command/testdata/show-json/modules/output.json rename to command/testdata/show-json/modules/output.json diff --git a/internal/command/testdata/show-json/moved-drift/main.tf b/command/testdata/show-json/moved-drift/main.tf similarity index 100% rename from internal/command/testdata/show-json/moved-drift/main.tf rename to command/testdata/show-json/moved-drift/main.tf diff --git a/internal/command/testdata/show-json/moved-drift/output.json b/command/testdata/show-json/moved-drift/output.json similarity index 100% rename from internal/command/testdata/show-json/moved-drift/output.json rename to command/testdata/show-json/moved-drift/output.json diff --git a/internal/command/testdata/show-json/moved-drift/terraform.tfstate b/command/testdata/show-json/moved-drift/terraform.tfstate similarity index 100% rename from internal/command/testdata/show-json/moved-drift/terraform.tfstate rename to command/testdata/show-json/moved-drift/terraform.tfstate diff --git a/internal/command/testdata/show-json/moved/main.tf b/command/testdata/show-json/moved/main.tf similarity index 100% rename from internal/command/testdata/show-json/moved/main.tf rename to command/testdata/show-json/moved/main.tf diff --git a/internal/command/testdata/show-json/moved/output.json b/command/testdata/show-json/moved/output.json similarity index 100% rename from internal/command/testdata/show-json/moved/output.json rename to command/testdata/show-json/moved/output.json diff --git a/internal/command/testdata/show-json/moved/terraform.tfstate b/command/testdata/show-json/moved/terraform.tfstate similarity index 100% rename from internal/command/testdata/show-json/moved/terraform.tfstate rename to command/testdata/show-json/moved/terraform.tfstate diff --git a/internal/command/testdata/show-json/multi-resource-update/main.tf b/command/testdata/show-json/multi-resource-update/main.tf similarity index 100% rename from internal/command/testdata/show-json/multi-resource-update/main.tf rename to command/testdata/show-json/multi-resource-update/main.tf diff --git a/internal/command/testdata/show-json/multi-resource-update/output.json b/command/testdata/show-json/multi-resource-update/output.json similarity index 100% rename from internal/command/testdata/show-json/multi-resource-update/output.json rename to command/testdata/show-json/multi-resource-update/output.json diff --git a/internal/command/testdata/show-json/multi-resource-update/terraform.tfstate b/command/testdata/show-json/multi-resource-update/terraform.tfstate similarity index 100% rename from internal/command/testdata/show-json/multi-resource-update/terraform.tfstate rename to command/testdata/show-json/multi-resource-update/terraform.tfstate diff --git a/internal/command/testdata/show-json/nested-module-error/main.tf b/command/testdata/show-json/nested-module-error/main.tf similarity index 100% rename from internal/command/testdata/show-json/nested-module-error/main.tf rename to command/testdata/show-json/nested-module-error/main.tf diff --git a/internal/command/testdata/show-json/nested-module-error/modules/main.tf b/command/testdata/show-json/nested-module-error/modules/main.tf similarity index 100% rename from internal/command/testdata/show-json/nested-module-error/modules/main.tf rename to command/testdata/show-json/nested-module-error/modules/main.tf diff --git a/internal/command/testdata/show-json/nested-module-error/modules/more-modules/main.tf b/command/testdata/show-json/nested-module-error/modules/more-modules/main.tf similarity index 100% rename from internal/command/testdata/show-json/nested-module-error/modules/more-modules/main.tf rename to command/testdata/show-json/nested-module-error/modules/more-modules/main.tf diff --git a/internal/command/testdata/show-json/nested-modules/main.tf b/command/testdata/show-json/nested-modules/main.tf similarity index 100% rename from internal/command/testdata/show-json/nested-modules/main.tf rename to command/testdata/show-json/nested-modules/main.tf diff --git a/internal/command/testdata/show-json/nested-modules/modules/main.tf b/command/testdata/show-json/nested-modules/modules/main.tf similarity index 100% rename from internal/command/testdata/show-json/nested-modules/modules/main.tf rename to command/testdata/show-json/nested-modules/modules/main.tf diff --git a/internal/command/testdata/show-json/nested-modules/modules/more-modules/main.tf b/command/testdata/show-json/nested-modules/modules/more-modules/main.tf similarity index 100% rename from internal/command/testdata/show-json/nested-modules/modules/more-modules/main.tf rename to command/testdata/show-json/nested-modules/modules/more-modules/main.tf diff --git a/internal/command/testdata/show-json/nested-modules/output.json b/command/testdata/show-json/nested-modules/output.json similarity index 100% rename from internal/command/testdata/show-json/nested-modules/output.json rename to command/testdata/show-json/nested-modules/output.json diff --git a/internal/command/testdata/show-json/provider-aliasing-conflict/child/main.tf b/command/testdata/show-json/provider-aliasing-conflict/child/main.tf similarity index 100% rename from internal/command/testdata/show-json/provider-aliasing-conflict/child/main.tf rename to command/testdata/show-json/provider-aliasing-conflict/child/main.tf diff --git a/internal/command/testdata/show-json/provider-aliasing-conflict/main.tf b/command/testdata/show-json/provider-aliasing-conflict/main.tf similarity index 100% rename from internal/command/testdata/show-json/provider-aliasing-conflict/main.tf rename to command/testdata/show-json/provider-aliasing-conflict/main.tf diff --git a/internal/command/testdata/show-json/provider-aliasing-conflict/output.json b/command/testdata/show-json/provider-aliasing-conflict/output.json similarity index 100% rename from internal/command/testdata/show-json/provider-aliasing-conflict/output.json rename to command/testdata/show-json/provider-aliasing-conflict/output.json diff --git a/internal/command/testdata/show-json/provider-aliasing-default/child/main.tf b/command/testdata/show-json/provider-aliasing-default/child/main.tf similarity index 100% rename from internal/command/testdata/show-json/provider-aliasing-default/child/main.tf rename to command/testdata/show-json/provider-aliasing-default/child/main.tf diff --git a/internal/command/testdata/show-json/provider-aliasing-default/child/nested-no-requirements/main.tf b/command/testdata/show-json/provider-aliasing-default/child/nested-no-requirements/main.tf similarity index 100% rename from internal/command/testdata/show-json/provider-aliasing-default/child/nested-no-requirements/main.tf rename to command/testdata/show-json/provider-aliasing-default/child/nested-no-requirements/main.tf diff --git a/internal/command/testdata/show-json/provider-aliasing-default/child/nested/main.tf b/command/testdata/show-json/provider-aliasing-default/child/nested/main.tf similarity index 100% rename from internal/command/testdata/show-json/provider-aliasing-default/child/nested/main.tf rename to command/testdata/show-json/provider-aliasing-default/child/nested/main.tf diff --git a/internal/command/testdata/show-json/provider-aliasing-default/main.tf b/command/testdata/show-json/provider-aliasing-default/main.tf similarity index 100% rename from internal/command/testdata/show-json/provider-aliasing-default/main.tf rename to command/testdata/show-json/provider-aliasing-default/main.tf diff --git a/internal/command/testdata/show-json/provider-aliasing-default/output.json b/command/testdata/show-json/provider-aliasing-default/output.json similarity index 100% rename from internal/command/testdata/show-json/provider-aliasing-default/output.json rename to command/testdata/show-json/provider-aliasing-default/output.json diff --git a/internal/command/testdata/show-json/provider-aliasing/child/main.tf b/command/testdata/show-json/provider-aliasing/child/main.tf similarity index 100% rename from internal/command/testdata/show-json/provider-aliasing/child/main.tf rename to command/testdata/show-json/provider-aliasing/child/main.tf diff --git a/internal/command/testdata/show-json/provider-aliasing/child/nested/main.tf b/command/testdata/show-json/provider-aliasing/child/nested/main.tf similarity index 100% rename from internal/command/testdata/show-json/provider-aliasing/child/nested/main.tf rename to command/testdata/show-json/provider-aliasing/child/nested/main.tf diff --git a/internal/command/testdata/show-json/provider-aliasing/main.tf b/command/testdata/show-json/provider-aliasing/main.tf similarity index 100% rename from internal/command/testdata/show-json/provider-aliasing/main.tf rename to command/testdata/show-json/provider-aliasing/main.tf diff --git a/internal/command/testdata/show-json/provider-aliasing/output.json b/command/testdata/show-json/provider-aliasing/output.json similarity index 100% rename from internal/command/testdata/show-json/provider-aliasing/output.json rename to command/testdata/show-json/provider-aliasing/output.json diff --git a/internal/command/testdata/show-json/provider-version-no-config/main.tf b/command/testdata/show-json/provider-version-no-config/main.tf similarity index 100% rename from internal/command/testdata/show-json/provider-version-no-config/main.tf rename to command/testdata/show-json/provider-version-no-config/main.tf diff --git a/internal/command/testdata/show-json/provider-version-no-config/output.json b/command/testdata/show-json/provider-version-no-config/output.json similarity index 100% rename from internal/command/testdata/show-json/provider-version-no-config/output.json rename to command/testdata/show-json/provider-version-no-config/output.json diff --git a/internal/command/testdata/show-json/provider-version/main.tf b/command/testdata/show-json/provider-version/main.tf similarity index 100% rename from internal/command/testdata/show-json/provider-version/main.tf rename to command/testdata/show-json/provider-version/main.tf diff --git a/internal/command/testdata/show-json/provider-version/output.json b/command/testdata/show-json/provider-version/output.json similarity index 100% rename from internal/command/testdata/show-json/provider-version/output.json rename to command/testdata/show-json/provider-version/output.json diff --git a/internal/command/testdata/show-json/requires-replace/main.tf b/command/testdata/show-json/requires-replace/main.tf similarity index 100% rename from internal/command/testdata/show-json/requires-replace/main.tf rename to command/testdata/show-json/requires-replace/main.tf diff --git a/internal/command/testdata/show-json/requires-replace/output.json b/command/testdata/show-json/requires-replace/output.json similarity index 100% rename from internal/command/testdata/show-json/requires-replace/output.json rename to command/testdata/show-json/requires-replace/output.json diff --git a/internal/command/testdata/show-json/requires-replace/terraform.tfstate b/command/testdata/show-json/requires-replace/terraform.tfstate similarity index 100% rename from internal/command/testdata/show-json/requires-replace/terraform.tfstate rename to command/testdata/show-json/requires-replace/terraform.tfstate diff --git a/internal/command/testdata/show-json/sensitive-values/main.tf b/command/testdata/show-json/sensitive-values/main.tf similarity index 100% rename from internal/command/testdata/show-json/sensitive-values/main.tf rename to command/testdata/show-json/sensitive-values/main.tf diff --git a/internal/command/testdata/show-json/sensitive-values/output.json b/command/testdata/show-json/sensitive-values/output.json similarity index 100% rename from internal/command/testdata/show-json/sensitive-values/output.json rename to command/testdata/show-json/sensitive-values/output.json diff --git a/internal/command/testdata/show-json/unknown-output/main.tf b/command/testdata/show-json/unknown-output/main.tf similarity index 100% rename from internal/command/testdata/show-json/unknown-output/main.tf rename to command/testdata/show-json/unknown-output/main.tf diff --git a/internal/command/testdata/show-json/unknown-output/output.json b/command/testdata/show-json/unknown-output/output.json similarity index 100% rename from internal/command/testdata/show-json/unknown-output/output.json rename to command/testdata/show-json/unknown-output/output.json diff --git a/internal/command/testdata/show/main.tf b/command/testdata/show/main.tf similarity index 100% rename from internal/command/testdata/show/main.tf rename to command/testdata/show/main.tf diff --git a/internal/command/testdata/state-list-backend-custom/.terraform/terraform.tfstate b/command/testdata/state-list-backend-custom/.terraform/terraform.tfstate similarity index 100% rename from internal/command/testdata/state-list-backend-custom/.terraform/terraform.tfstate rename to command/testdata/state-list-backend-custom/.terraform/terraform.tfstate diff --git a/internal/command/testdata/state-list-backend-custom/local-state.tfstate b/command/testdata/state-list-backend-custom/local-state.tfstate similarity index 100% rename from internal/command/testdata/state-list-backend-custom/local-state.tfstate rename to command/testdata/state-list-backend-custom/local-state.tfstate diff --git a/internal/command/testdata/state-list-backend-custom/main.tf b/command/testdata/state-list-backend-custom/main.tf similarity index 100% rename from internal/command/testdata/state-list-backend-custom/main.tf rename to command/testdata/state-list-backend-custom/main.tf diff --git a/internal/command/testdata/state-list-backend-default/.terraform/terraform.tfstate b/command/testdata/state-list-backend-default/.terraform/terraform.tfstate similarity index 100% rename from internal/command/testdata/state-list-backend-default/.terraform/terraform.tfstate rename to command/testdata/state-list-backend-default/.terraform/terraform.tfstate diff --git a/internal/command/testdata/state-list-backend-default/main.tf b/command/testdata/state-list-backend-default/main.tf similarity index 100% rename from internal/command/testdata/state-list-backend-default/main.tf rename to command/testdata/state-list-backend-default/main.tf diff --git a/internal/command/testdata/state-list-backend-default/terraform.tfstate b/command/testdata/state-list-backend-default/terraform.tfstate similarity index 100% rename from internal/command/testdata/state-list-backend-default/terraform.tfstate rename to command/testdata/state-list-backend-default/terraform.tfstate diff --git a/internal/command/testdata/state-list-nested-modules/terraform.tfstate b/command/testdata/state-list-nested-modules/terraform.tfstate similarity index 100% rename from internal/command/testdata/state-list-nested-modules/terraform.tfstate rename to command/testdata/state-list-nested-modules/terraform.tfstate diff --git a/internal/command/testdata/state-pull-backend/.terraform/terraform.tfstate b/command/testdata/state-pull-backend/.terraform/terraform.tfstate similarity index 100% rename from internal/command/testdata/state-pull-backend/.terraform/terraform.tfstate rename to command/testdata/state-pull-backend/.terraform/terraform.tfstate diff --git a/internal/command/testdata/state-pull-backend/local-state.tfstate b/command/testdata/state-pull-backend/local-state.tfstate similarity index 100% rename from internal/command/testdata/state-pull-backend/local-state.tfstate rename to command/testdata/state-pull-backend/local-state.tfstate diff --git a/internal/command/testdata/state-pull-backend/main.tf b/command/testdata/state-pull-backend/main.tf similarity index 100% rename from internal/command/testdata/state-pull-backend/main.tf rename to command/testdata/state-pull-backend/main.tf diff --git a/internal/command/testdata/state-push-bad-lineage/.terraform/terraform.tfstate b/command/testdata/state-push-bad-lineage/.terraform/terraform.tfstate similarity index 100% rename from internal/command/testdata/state-push-bad-lineage/.terraform/terraform.tfstate rename to command/testdata/state-push-bad-lineage/.terraform/terraform.tfstate diff --git a/internal/command/testdata/state-push-bad-lineage/local-state.tfstate b/command/testdata/state-push-bad-lineage/local-state.tfstate similarity index 100% rename from internal/command/testdata/state-push-bad-lineage/local-state.tfstate rename to command/testdata/state-push-bad-lineage/local-state.tfstate diff --git a/internal/command/testdata/state-push-bad-lineage/main.tf b/command/testdata/state-push-bad-lineage/main.tf similarity index 100% rename from internal/command/testdata/state-push-bad-lineage/main.tf rename to command/testdata/state-push-bad-lineage/main.tf diff --git a/internal/command/testdata/state-push-bad-lineage/replace.tfstate b/command/testdata/state-push-bad-lineage/replace.tfstate similarity index 100% rename from internal/command/testdata/state-push-bad-lineage/replace.tfstate rename to command/testdata/state-push-bad-lineage/replace.tfstate diff --git a/internal/command/testdata/state-push-good/.terraform/terraform.tfstate b/command/testdata/state-push-good/.terraform/terraform.tfstate similarity index 100% rename from internal/command/testdata/state-push-good/.terraform/terraform.tfstate rename to command/testdata/state-push-good/.terraform/terraform.tfstate diff --git a/internal/command/testdata/state-push-good/main.tf b/command/testdata/state-push-good/main.tf similarity index 100% rename from internal/command/testdata/state-push-good/main.tf rename to command/testdata/state-push-good/main.tf diff --git a/internal/command/testdata/state-push-good/replace.tfstate b/command/testdata/state-push-good/replace.tfstate similarity index 100% rename from internal/command/testdata/state-push-good/replace.tfstate rename to command/testdata/state-push-good/replace.tfstate diff --git a/internal/command/testdata/state-push-replace-match/.terraform/terraform.tfstate b/command/testdata/state-push-replace-match/.terraform/terraform.tfstate similarity index 100% rename from internal/command/testdata/state-push-replace-match/.terraform/terraform.tfstate rename to command/testdata/state-push-replace-match/.terraform/terraform.tfstate diff --git a/internal/command/testdata/state-push-replace-match/local-state.tfstate b/command/testdata/state-push-replace-match/local-state.tfstate similarity index 100% rename from internal/command/testdata/state-push-replace-match/local-state.tfstate rename to command/testdata/state-push-replace-match/local-state.tfstate diff --git a/internal/command/testdata/state-push-replace-match/main.tf b/command/testdata/state-push-replace-match/main.tf similarity index 100% rename from internal/command/testdata/state-push-replace-match/main.tf rename to command/testdata/state-push-replace-match/main.tf diff --git a/internal/command/testdata/state-push-replace-match/replace.tfstate b/command/testdata/state-push-replace-match/replace.tfstate similarity index 100% rename from internal/command/testdata/state-push-replace-match/replace.tfstate rename to command/testdata/state-push-replace-match/replace.tfstate diff --git a/internal/command/testdata/state-push-serial-newer/.terraform/terraform.tfstate b/command/testdata/state-push-serial-newer/.terraform/terraform.tfstate similarity index 100% rename from internal/command/testdata/state-push-serial-newer/.terraform/terraform.tfstate rename to command/testdata/state-push-serial-newer/.terraform/terraform.tfstate diff --git a/internal/command/testdata/state-push-serial-newer/local-state.tfstate b/command/testdata/state-push-serial-newer/local-state.tfstate similarity index 100% rename from internal/command/testdata/state-push-serial-newer/local-state.tfstate rename to command/testdata/state-push-serial-newer/local-state.tfstate diff --git a/internal/command/testdata/state-push-serial-newer/main.tf b/command/testdata/state-push-serial-newer/main.tf similarity index 100% rename from internal/command/testdata/state-push-serial-newer/main.tf rename to command/testdata/state-push-serial-newer/main.tf diff --git a/internal/command/testdata/state-push-serial-newer/replace.tfstate b/command/testdata/state-push-serial-newer/replace.tfstate similarity index 100% rename from internal/command/testdata/state-push-serial-newer/replace.tfstate rename to command/testdata/state-push-serial-newer/replace.tfstate diff --git a/internal/command/testdata/state-push-serial-older/.terraform/terraform.tfstate b/command/testdata/state-push-serial-older/.terraform/terraform.tfstate similarity index 100% rename from internal/command/testdata/state-push-serial-older/.terraform/terraform.tfstate rename to command/testdata/state-push-serial-older/.terraform/terraform.tfstate diff --git a/internal/command/testdata/state-push-serial-older/local-state.tfstate b/command/testdata/state-push-serial-older/local-state.tfstate similarity index 100% rename from internal/command/testdata/state-push-serial-older/local-state.tfstate rename to command/testdata/state-push-serial-older/local-state.tfstate diff --git a/internal/command/testdata/state-push-serial-older/main.tf b/command/testdata/state-push-serial-older/main.tf similarity index 100% rename from internal/command/testdata/state-push-serial-older/main.tf rename to command/testdata/state-push-serial-older/main.tf diff --git a/internal/command/testdata/state-push-serial-older/replace.tfstate b/command/testdata/state-push-serial-older/replace.tfstate similarity index 100% rename from internal/command/testdata/state-push-serial-older/replace.tfstate rename to command/testdata/state-push-serial-older/replace.tfstate diff --git a/internal/command/testdata/statelocker.go b/command/testdata/statelocker.go similarity index 89% rename from internal/command/testdata/statelocker.go rename to command/testdata/statelocker.go index a31708605ae8..98e13a23a45a 100644 --- a/internal/command/testdata/statelocker.go +++ b/command/testdata/statelocker.go @@ -11,8 +11,8 @@ import ( "syscall" "time" - "github.com/hashicorp/terraform/internal/command/clistate" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/command/clistate" + "github.com/hashicorp/terraform/states/statemgr" ) func main() { diff --git a/internal/command/testdata/test-fails/test-fails.tf b/command/testdata/test-fails/test-fails.tf similarity index 100% rename from internal/command/testdata/test-fails/test-fails.tf rename to command/testdata/test-fails/test-fails.tf diff --git a/internal/command/testdata/test-fails/tests/hello/hello.tf b/command/testdata/test-fails/tests/hello/hello.tf similarity index 100% rename from internal/command/testdata/test-fails/tests/hello/hello.tf rename to command/testdata/test-fails/tests/hello/hello.tf diff --git a/internal/command/testdata/test-passes/test-passes.tf b/command/testdata/test-passes/test-passes.tf similarity index 100% rename from internal/command/testdata/test-passes/test-passes.tf rename to command/testdata/test-passes/test-passes.tf diff --git a/internal/command/testdata/test-passes/tests/hello/hello.tf b/command/testdata/test-passes/tests/hello/hello.tf similarity index 100% rename from internal/command/testdata/test-passes/tests/hello/hello.tf rename to command/testdata/test-passes/tests/hello/hello.tf diff --git a/internal/command/testdata/validate-invalid/incorrectmodulename/main.tf b/command/testdata/validate-invalid/incorrectmodulename/main.tf similarity index 100% rename from internal/command/testdata/validate-invalid/incorrectmodulename/main.tf rename to command/testdata/validate-invalid/incorrectmodulename/main.tf diff --git a/internal/command/testdata/validate-invalid/incorrectmodulename/output.json b/command/testdata/validate-invalid/incorrectmodulename/output.json similarity index 100% rename from internal/command/testdata/validate-invalid/incorrectmodulename/output.json rename to command/testdata/validate-invalid/incorrectmodulename/output.json diff --git a/internal/command/testdata/validate-invalid/interpolation/main.tf b/command/testdata/validate-invalid/interpolation/main.tf similarity index 100% rename from internal/command/testdata/validate-invalid/interpolation/main.tf rename to command/testdata/validate-invalid/interpolation/main.tf diff --git a/internal/command/testdata/validate-invalid/interpolation/output.json b/command/testdata/validate-invalid/interpolation/output.json similarity index 100% rename from internal/command/testdata/validate-invalid/interpolation/output.json rename to command/testdata/validate-invalid/interpolation/output.json diff --git a/internal/command/testdata/validate-invalid/main.tf b/command/testdata/validate-invalid/main.tf similarity index 100% rename from internal/command/testdata/validate-invalid/main.tf rename to command/testdata/validate-invalid/main.tf diff --git a/internal/command/testdata/validate-invalid/missing_defined_var/main.tf b/command/testdata/validate-invalid/missing_defined_var/main.tf similarity index 100% rename from internal/command/testdata/validate-invalid/missing_defined_var/main.tf rename to command/testdata/validate-invalid/missing_defined_var/main.tf diff --git a/internal/command/testdata/validate-invalid/missing_defined_var/output.json b/command/testdata/validate-invalid/missing_defined_var/output.json similarity index 100% rename from internal/command/testdata/validate-invalid/missing_defined_var/output.json rename to command/testdata/validate-invalid/missing_defined_var/output.json diff --git a/internal/command/testdata/validate-invalid/missing_quote/main.tf b/command/testdata/validate-invalid/missing_quote/main.tf similarity index 100% rename from internal/command/testdata/validate-invalid/missing_quote/main.tf rename to command/testdata/validate-invalid/missing_quote/main.tf diff --git a/internal/command/testdata/validate-invalid/missing_quote/output.json b/command/testdata/validate-invalid/missing_quote/output.json similarity index 100% rename from internal/command/testdata/validate-invalid/missing_quote/output.json rename to command/testdata/validate-invalid/missing_quote/output.json diff --git a/internal/command/testdata/validate-invalid/missing_var/main.tf b/command/testdata/validate-invalid/missing_var/main.tf similarity index 100% rename from internal/command/testdata/validate-invalid/missing_var/main.tf rename to command/testdata/validate-invalid/missing_var/main.tf diff --git a/internal/command/testdata/validate-invalid/missing_var/output.json b/command/testdata/validate-invalid/missing_var/output.json similarity index 100% rename from internal/command/testdata/validate-invalid/missing_var/output.json rename to command/testdata/validate-invalid/missing_var/output.json diff --git a/internal/command/testdata/validate-invalid/multiple_modules/main.tf b/command/testdata/validate-invalid/multiple_modules/main.tf similarity index 100% rename from internal/command/testdata/validate-invalid/multiple_modules/main.tf rename to command/testdata/validate-invalid/multiple_modules/main.tf diff --git a/internal/command/testdata/validate-invalid/multiple_modules/output.json b/command/testdata/validate-invalid/multiple_modules/output.json similarity index 100% rename from internal/command/testdata/validate-invalid/multiple_modules/output.json rename to command/testdata/validate-invalid/multiple_modules/output.json diff --git a/internal/command/testdata/validate-invalid/multiple_providers/main.tf b/command/testdata/validate-invalid/multiple_providers/main.tf similarity index 100% rename from internal/command/testdata/validate-invalid/multiple_providers/main.tf rename to command/testdata/validate-invalid/multiple_providers/main.tf diff --git a/internal/command/testdata/validate-invalid/multiple_providers/output.json b/command/testdata/validate-invalid/multiple_providers/output.json similarity index 100% rename from internal/command/testdata/validate-invalid/multiple_providers/output.json rename to command/testdata/validate-invalid/multiple_providers/output.json diff --git a/internal/command/testdata/validate-invalid/multiple_resources/main.tf b/command/testdata/validate-invalid/multiple_resources/main.tf similarity index 100% rename from internal/command/testdata/validate-invalid/multiple_resources/main.tf rename to command/testdata/validate-invalid/multiple_resources/main.tf diff --git a/internal/command/testdata/validate-invalid/multiple_resources/output.json b/command/testdata/validate-invalid/multiple_resources/output.json similarity index 100% rename from internal/command/testdata/validate-invalid/multiple_resources/output.json rename to command/testdata/validate-invalid/multiple_resources/output.json diff --git a/internal/command/testdata/validate-invalid/output.json b/command/testdata/validate-invalid/output.json similarity index 100% rename from internal/command/testdata/validate-invalid/output.json rename to command/testdata/validate-invalid/output.json diff --git a/internal/command/testdata/validate-invalid/outputs/main.tf b/command/testdata/validate-invalid/outputs/main.tf similarity index 100% rename from internal/command/testdata/validate-invalid/outputs/main.tf rename to command/testdata/validate-invalid/outputs/main.tf diff --git a/internal/command/testdata/validate-invalid/outputs/output.json b/command/testdata/validate-invalid/outputs/output.json similarity index 100% rename from internal/command/testdata/validate-invalid/outputs/output.json rename to command/testdata/validate-invalid/outputs/output.json diff --git a/internal/command/testdata/validate-valid/main.tf b/command/testdata/validate-valid/main.tf similarity index 100% rename from internal/command/testdata/validate-valid/main.tf rename to command/testdata/validate-valid/main.tf diff --git a/internal/command/testdata/validate-valid/output.json b/command/testdata/validate-valid/output.json similarity index 100% rename from internal/command/testdata/validate-valid/output.json rename to command/testdata/validate-valid/output.json diff --git a/internal/command/testdata/validate-valid/with-tfvars-file/main.tf b/command/testdata/validate-valid/with-tfvars-file/main.tf similarity index 100% rename from internal/command/testdata/validate-valid/with-tfvars-file/main.tf rename to command/testdata/validate-valid/with-tfvars-file/main.tf diff --git a/internal/command/testdata/validate-valid/with-tfvars-file/terraform.tfvars b/command/testdata/validate-valid/with-tfvars-file/terraform.tfvars similarity index 100% rename from internal/command/testdata/validate-valid/with-tfvars-file/terraform.tfvars rename to command/testdata/validate-valid/with-tfvars-file/terraform.tfvars diff --git a/internal/command/testdata/variables/main.tf b/command/testdata/variables/main.tf similarity index 100% rename from internal/command/testdata/variables/main.tf rename to command/testdata/variables/main.tf diff --git a/internal/command/ui_input.go b/command/ui_input.go similarity index 98% rename from internal/command/ui_input.go rename to command/ui_input.go index 071982dec283..5492a0ab5cf3 100644 --- a/internal/command/ui_input.go +++ b/command/ui_input.go @@ -16,7 +16,7 @@ import ( "unicode" "github.com/bgentry/speakeasy" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/terraform" "github.com/mattn/go-isatty" "github.com/mitchellh/colorstring" ) diff --git a/internal/command/ui_input_test.go b/command/ui_input_test.go similarity index 97% rename from internal/command/ui_input_test.go rename to command/ui_input_test.go index d08cb0a2450b..7bda3962d309 100644 --- a/internal/command/ui_input_test.go +++ b/command/ui_input_test.go @@ -9,7 +9,7 @@ import ( "testing" "time" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/terraform" ) func TestUIInput_impl(t *testing.T) { diff --git a/internal/command/unlock.go b/command/unlock.go similarity index 95% rename from internal/command/unlock.go rename to command/unlock.go index 1cb915e065a9..f2ce6b144db6 100644 --- a/internal/command/unlock.go +++ b/command/unlock.go @@ -5,10 +5,10 @@ import ( "fmt" "strings" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/states/statemgr" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" "github.com/mitchellh/cli" ) diff --git a/internal/command/unlock_test.go b/command/unlock_test.go similarity index 94% rename from internal/command/unlock_test.go rename to command/unlock_test.go index 9822b38426c7..4ba9a9b53144 100644 --- a/internal/command/unlock_test.go +++ b/command/unlock_test.go @@ -4,10 +4,10 @@ import ( "os" "testing" - "github.com/hashicorp/terraform/internal/backend/remote-state/inmem" + "github.com/hashicorp/terraform/backend/remote-state/inmem" "github.com/mitchellh/cli" - legacy "github.com/hashicorp/terraform/internal/legacy/terraform" + legacy "github.com/hashicorp/terraform/legacy/terraform" ) // Since we can't unlock a local state file, just test that calling unlock diff --git a/internal/command/untaint.go b/command/untaint.go similarity index 94% rename from internal/command/untaint.go rename to command/untaint.go index d02a794cfeab..1860ca0fba8d 100644 --- a/internal/command/untaint.go +++ b/command/untaint.go @@ -4,13 +4,13 @@ import ( "fmt" "strings" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/clistate" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/clistate" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" ) // UntaintCommand is a cli.Command implementation that manually untaints diff --git a/internal/command/untaint_test.go b/command/untaint_test.go similarity index 99% rename from internal/command/untaint_test.go rename to command/untaint_test.go index cc193125e474..e1aa0777107c 100644 --- a/internal/command/untaint_test.go +++ b/command/untaint_test.go @@ -6,8 +6,8 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/states" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/states" "github.com/mitchellh/cli" ) diff --git a/internal/command/validate.go b/command/validate.go similarity index 94% rename from internal/command/validate.go rename to command/validate.go index 110fcec8c32e..fccc201fe325 100644 --- a/internal/command/validate.go +++ b/command/validate.go @@ -5,10 +5,10 @@ import ( "path/filepath" "strings" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" ) // ValidateCommand is a Command implementation that validates the terraform files diff --git a/internal/command/validate_test.go b/command/validate_test.go similarity index 97% rename from internal/command/validate_test.go rename to command/validate_test.go index 969e79683fab..6015f48c1ab0 100644 --- a/internal/command/validate_test.go +++ b/command/validate_test.go @@ -11,9 +11,9 @@ import ( "github.com/google/go-cmp/cmp" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/terminal" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/terminal" ) func setupTest(t *testing.T, fixturepath string, args ...string) (*terminal.TestOutput, int) { diff --git a/internal/command/version.go b/command/version.go similarity index 96% rename from internal/command/version.go rename to command/version.go index 7fef59202daa..b940b4b26356 100644 --- a/internal/command/version.go +++ b/command/version.go @@ -7,9 +7,9 @@ import ( "sort" "strings" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/depsfile" - "github.com/hashicorp/terraform/internal/getproviders" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/depsfile" + "github.com/hashicorp/terraform/getproviders" ) // VersionCommand is a Command implementation prints the version. diff --git a/internal/command/version_test.go b/command/version_test.go similarity index 97% rename from internal/command/version_test.go rename to command/version_test.go index 3ec5a4b86399..b9b153cbb40e 100644 --- a/internal/command/version_test.go +++ b/command/version_test.go @@ -5,9 +5,9 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/depsfile" - "github.com/hashicorp/terraform/internal/getproviders" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/depsfile" + "github.com/hashicorp/terraform/getproviders" "github.com/mitchellh/cli" ) diff --git a/internal/command/views/apply.go b/command/views/apply.go similarity index 91% rename from internal/command/views/apply.go rename to command/views/apply.go index ec07f6ad9ad0..988924f99948 100644 --- a/internal/command/views/apply.go +++ b/command/views/apply.go @@ -3,12 +3,12 @@ package views import ( "fmt" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/format" - "github.com/hashicorp/terraform/internal/command/views/json" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/format" + "github.com/hashicorp/terraform/command/views/json" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" ) // The Apply view is used for the apply command. diff --git a/internal/command/views/apply_test.go b/command/views/apply_test.go similarity index 96% rename from internal/command/views/apply_test.go rename to command/views/apply_test.go index d8bc71c80aab..f4b9265bd066 100644 --- a/internal/command/views/apply_test.go +++ b/command/views/apply_test.go @@ -5,10 +5,10 @@ import ( "strings" "testing" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/lang/marks" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/terminal" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/lang/marks" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/terminal" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/command/views/hook_count.go b/command/views/hook_count.go similarity index 91% rename from internal/command/views/hook_count.go rename to command/views/hook_count.go index 054c9da38d42..25e1a5e7ddf1 100644 --- a/internal/command/views/hook_count.go +++ b/command/views/hook_count.go @@ -5,10 +5,10 @@ import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/terraform" ) // countHook is a hook that counts the number of resources diff --git a/internal/command/views/hook_count_test.go b/command/views/hook_count_test.go similarity index 96% rename from internal/command/views/hook_count_test.go rename to command/views/hook_count_test.go index 3cf51d4dd42d..b5f670736c65 100644 --- a/internal/command/views/hook_count_test.go +++ b/command/views/hook_count_test.go @@ -6,12 +6,12 @@ import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/terraform" - legacy "github.com/hashicorp/terraform/internal/legacy/terraform" + legacy "github.com/hashicorp/terraform/legacy/terraform" ) func TestCountHook_impl(t *testing.T) { diff --git a/internal/command/views/hook_json.go b/command/views/hook_json.go similarity index 93% rename from internal/command/views/hook_json.go rename to command/views/hook_json.go index 38e24de39d6c..18ff86ada86f 100644 --- a/internal/command/views/hook_json.go +++ b/command/views/hook_json.go @@ -9,12 +9,12 @@ import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/command/format" - "github.com/hashicorp/terraform/internal/command/views/json" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/command/format" + "github.com/hashicorp/terraform/command/views/json" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/terraform" ) // How long to wait between sending heartbeat/progress messages diff --git a/internal/command/views/hook_json_test.go b/command/views/hook_json_test.go similarity index 97% rename from internal/command/views/hook_json_test.go rename to command/views/hook_json_test.go index cb1cbc920bd7..cd451559f825 100644 --- a/internal/command/views/hook_json_test.go +++ b/command/views/hook_json_test.go @@ -6,11 +6,11 @@ import ( "testing" "time" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/terminal" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/terminal" + "github.com/hashicorp/terraform/terraform" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/command/views/hook_ui.go b/command/views/hook_ui.go similarity index 96% rename from internal/command/views/hook_ui.go rename to command/views/hook_ui.go index 2c5c0f5704fc..c10b7878f485 100644 --- a/internal/command/views/hook_ui.go +++ b/command/views/hook_ui.go @@ -11,12 +11,12 @@ import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/command/format" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/command/format" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/terraform" ) const defaultPeriodicUiTimer = 10 * time.Second diff --git a/internal/command/views/hook_ui_test.go b/command/views/hook_ui_test.go similarity index 97% rename from internal/command/views/hook_ui_test.go rename to command/views/hook_ui_test.go index bbde3b686643..1720e2af7501 100644 --- a/internal/command/views/hook_ui_test.go +++ b/command/views/hook_ui_test.go @@ -10,13 +10,13 @@ import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/terminal" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/terminal" + "github.com/hashicorp/terraform/terraform" ) // Test the PreApply hook for creating a new resource diff --git a/internal/command/views/json/change.go b/command/views/json/change.go similarity index 98% rename from internal/command/views/json/change.go rename to command/views/json/change.go index 60439e509017..128c81f8a82c 100644 --- a/internal/command/views/json/change.go +++ b/command/views/json/change.go @@ -3,7 +3,7 @@ package json import ( "fmt" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/plans" ) func NewResourceInstanceChange(change *plans.ResourceInstanceChangeSrc) *ResourceInstanceChange { diff --git a/internal/command/views/json/change_summary.go b/command/views/json/change_summary.go similarity index 100% rename from internal/command/views/json/change_summary.go rename to command/views/json/change_summary.go diff --git a/internal/command/views/json/diagnostic.go b/command/views/json/diagnostic.go similarity index 99% rename from internal/command/views/json/diagnostic.go rename to command/views/json/diagnostic.go index 1175792c72a2..551def16ba6a 100644 --- a/internal/command/views/json/diagnostic.go +++ b/command/views/json/diagnostic.go @@ -11,8 +11,8 @@ import ( "github.com/hashicorp/hcl/v2/hcled" "github.com/hashicorp/hcl/v2/hclparse" "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/hashicorp/terraform/internal/lang/marks" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/lang/marks" + "github.com/hashicorp/terraform/tfdiags" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/command/views/json/diagnostic_test.go b/command/views/json/diagnostic_test.go similarity index 99% rename from internal/command/views/json/diagnostic_test.go rename to command/views/json/diagnostic_test.go index 422dade9b3cb..fdc7750dbf17 100644 --- a/internal/command/views/json/diagnostic_test.go +++ b/command/views/json/diagnostic_test.go @@ -12,8 +12,8 @@ import ( "github.com/google/go-cmp/cmp" "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hcltest" - "github.com/hashicorp/terraform/internal/lang/marks" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/lang/marks" + "github.com/hashicorp/terraform/tfdiags" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/command/views/json/function.go b/command/views/json/function.go similarity index 100% rename from internal/command/views/json/function.go rename to command/views/json/function.go diff --git a/internal/command/views/json/function_test.go b/command/views/json/function_test.go similarity index 100% rename from internal/command/views/json/function_test.go rename to command/views/json/function_test.go diff --git a/internal/command/views/json/hook.go b/command/views/json/hook.go similarity index 99% rename from internal/command/views/json/hook.go rename to command/views/json/hook.go index 142a4d1fd199..c619e07ae67f 100644 --- a/internal/command/views/json/hook.go +++ b/command/views/json/hook.go @@ -4,8 +4,8 @@ import ( "fmt" "time" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/plans" ) type Hook interface { diff --git a/internal/command/views/json/message_types.go b/command/views/json/message_types.go similarity index 100% rename from internal/command/views/json/message_types.go rename to command/views/json/message_types.go diff --git a/internal/command/views/json/output.go b/command/views/json/output.go similarity index 91% rename from internal/command/views/json/output.go rename to command/views/json/output.go index c9648c56260b..65bfc883471c 100644 --- a/internal/command/views/json/output.go +++ b/command/views/json/output.go @@ -6,9 +6,9 @@ import ( ctyjson "github.com/zclconf/go-cty/cty/json" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/tfdiags" ) type Output struct { diff --git a/internal/command/views/json/output_test.go b/command/views/json/output_test.go similarity index 94% rename from internal/command/views/json/output_test.go rename to command/views/json/output_test.go index 0fa15e22d6dd..22acc42fb1fc 100644 --- a/internal/command/views/json/output_test.go +++ b/command/views/json/output_test.go @@ -5,10 +5,10 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/lang/marks" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/lang/marks" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/states" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/command/views/json/resource_addr.go b/command/views/json/resource_addr.go similarity index 95% rename from internal/command/views/json/resource_addr.go rename to command/views/json/resource_addr.go index 27ff502a2ce1..414ce33d8652 100644 --- a/internal/command/views/json/resource_addr.go +++ b/command/views/json/resource_addr.go @@ -4,7 +4,7 @@ import ( "github.com/zclconf/go-cty/cty" ctyjson "github.com/zclconf/go-cty/cty/json" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) type ResourceAddr struct { diff --git a/internal/command/views/json/testdata/diagnostic/error-whose-range-starts-at-a-newline.json b/command/views/json/testdata/diagnostic/error-whose-range-starts-at-a-newline.json similarity index 100% rename from internal/command/views/json/testdata/diagnostic/error-whose-range-starts-at-a-newline.json rename to command/views/json/testdata/diagnostic/error-whose-range-starts-at-a-newline.json diff --git a/internal/command/views/json/testdata/diagnostic/error-with-empty-highlight-range-at-end-of-source-code.json b/command/views/json/testdata/diagnostic/error-with-empty-highlight-range-at-end-of-source-code.json similarity index 100% rename from internal/command/views/json/testdata/diagnostic/error-with-empty-highlight-range-at-end-of-source-code.json rename to command/views/json/testdata/diagnostic/error-with-empty-highlight-range-at-end-of-source-code.json diff --git a/internal/command/views/json/testdata/diagnostic/error-with-multi-line-snippet.json b/command/views/json/testdata/diagnostic/error-with-multi-line-snippet.json similarity index 100% rename from internal/command/views/json/testdata/diagnostic/error-with-multi-line-snippet.json rename to command/views/json/testdata/diagnostic/error-with-multi-line-snippet.json diff --git a/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-expression-referring-to-a-collection-containing-a-sensitive-value.json b/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-expression-referring-to-a-collection-containing-a-sensitive-value.json similarity index 100% rename from internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-expression-referring-to-a-collection-containing-a-sensitive-value.json rename to command/views/json/testdata/diagnostic/error-with-source-code-subject-and-expression-referring-to-a-collection-containing-a-sensitive-value.json diff --git a/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-expression-referring-to-sensitive-value-when-not-caused-by-sensitive-values.json b/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-expression-referring-to-sensitive-value-when-not-caused-by-sensitive-values.json similarity index 100% rename from internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-expression-referring-to-sensitive-value-when-not-caused-by-sensitive-values.json rename to command/views/json/testdata/diagnostic/error-with-source-code-subject-and-expression-referring-to-sensitive-value-when-not-caused-by-sensitive-values.json diff --git a/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-expression-referring-to-sensitive-value.json b/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-expression-referring-to-sensitive-value.json similarity index 100% rename from internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-expression-referring-to-sensitive-value.json rename to command/views/json/testdata/diagnostic/error-with-source-code-subject-and-expression-referring-to-sensitive-value.json diff --git a/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-known-expression.json b/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-known-expression.json similarity index 100% rename from internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-known-expression.json rename to command/views/json/testdata/diagnostic/error-with-source-code-subject-and-known-expression.json diff --git a/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-unknown-expression-of-unknown-type-when-not-caused-by-unknown-values.json b/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-unknown-expression-of-unknown-type-when-not-caused-by-unknown-values.json similarity index 100% rename from internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-unknown-expression-of-unknown-type-when-not-caused-by-unknown-values.json rename to command/views/json/testdata/diagnostic/error-with-source-code-subject-and-unknown-expression-of-unknown-type-when-not-caused-by-unknown-values.json diff --git a/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-unknown-expression-of-unknown-type.json b/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-unknown-expression-of-unknown-type.json similarity index 100% rename from internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-unknown-expression-of-unknown-type.json rename to command/views/json/testdata/diagnostic/error-with-source-code-subject-and-unknown-expression-of-unknown-type.json diff --git a/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-unknown-string-expression.json b/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-unknown-string-expression.json similarity index 100% rename from internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-and-unknown-string-expression.json rename to command/views/json/testdata/diagnostic/error-with-source-code-subject-and-unknown-string-expression.json diff --git a/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-but-no-context.json b/command/views/json/testdata/diagnostic/error-with-source-code-subject-but-no-context.json similarity index 100% rename from internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-but-no-context.json rename to command/views/json/testdata/diagnostic/error-with-source-code-subject-but-no-context.json diff --git a/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-with-multiple-expression-values.json b/command/views/json/testdata/diagnostic/error-with-source-code-subject-with-multiple-expression-values.json similarity index 100% rename from internal/command/views/json/testdata/diagnostic/error-with-source-code-subject-with-multiple-expression-values.json rename to command/views/json/testdata/diagnostic/error-with-source-code-subject-with-multiple-expression-values.json diff --git a/internal/command/views/json/testdata/diagnostic/error-with-source-code-subject.json b/command/views/json/testdata/diagnostic/error-with-source-code-subject.json similarity index 100% rename from internal/command/views/json/testdata/diagnostic/error-with-source-code-subject.json rename to command/views/json/testdata/diagnostic/error-with-source-code-subject.json diff --git a/internal/command/views/json/testdata/diagnostic/error-with-source-code-unavailable.json b/command/views/json/testdata/diagnostic/error-with-source-code-unavailable.json similarity index 100% rename from internal/command/views/json/testdata/diagnostic/error-with-source-code-unavailable.json rename to command/views/json/testdata/diagnostic/error-with-source-code-unavailable.json diff --git a/internal/command/views/json/testdata/diagnostic/error-with-unset-highlight-end-position.json b/command/views/json/testdata/diagnostic/error-with-unset-highlight-end-position.json similarity index 100% rename from internal/command/views/json/testdata/diagnostic/error-with-unset-highlight-end-position.json rename to command/views/json/testdata/diagnostic/error-with-unset-highlight-end-position.json diff --git a/internal/command/views/json/testdata/diagnostic/sourceless-warning.json b/command/views/json/testdata/diagnostic/sourceless-warning.json similarity index 100% rename from internal/command/views/json/testdata/diagnostic/sourceless-warning.json rename to command/views/json/testdata/diagnostic/sourceless-warning.json diff --git a/internal/command/views/json_view.go b/command/views/json_view.go similarity index 96% rename from internal/command/views/json_view.go rename to command/views/json_view.go index a1493bc4def6..54cdbc06e544 100644 --- a/internal/command/views/json_view.go +++ b/command/views/json_view.go @@ -5,8 +5,8 @@ import ( "fmt" "github.com/hashicorp/go-hclog" - "github.com/hashicorp/terraform/internal/command/views/json" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/command/views/json" + "github.com/hashicorp/terraform/tfdiags" tfversion "github.com/hashicorp/terraform/version" ) diff --git a/internal/command/views/json_view_test.go b/command/views/json_view_test.go similarity index 97% rename from internal/command/views/json_view_test.go rename to command/views/json_view_test.go index 6bb5c4913241..225077bfe620 100644 --- a/internal/command/views/json_view_test.go +++ b/command/views/json_view_test.go @@ -8,11 +8,11 @@ import ( "time" "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/addrs" - viewsjson "github.com/hashicorp/terraform/internal/command/views/json" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/terminal" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + viewsjson "github.com/hashicorp/terraform/command/views/json" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/terminal" + "github.com/hashicorp/terraform/tfdiags" tfversion "github.com/hashicorp/terraform/version" ) diff --git a/internal/command/views/operation.go b/command/views/operation.go similarity index 92% rename from internal/command/views/operation.go rename to command/views/operation.go index a0a8a96f9342..f63f43c8b95c 100644 --- a/internal/command/views/operation.go +++ b/command/views/operation.go @@ -5,17 +5,17 @@ import ( "fmt" "strings" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/format" - "github.com/hashicorp/terraform/internal/command/jsonformat" - "github.com/hashicorp/terraform/internal/command/jsonplan" - "github.com/hashicorp/terraform/internal/command/jsonprovider" - "github.com/hashicorp/terraform/internal/command/views/json" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states/statefile" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/format" + "github.com/hashicorp/terraform/command/jsonformat" + "github.com/hashicorp/terraform/command/jsonplan" + "github.com/hashicorp/terraform/command/jsonprovider" + "github.com/hashicorp/terraform/command/views/json" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/states/statefile" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" ) type Operation interface { diff --git a/internal/command/views/operation_test.go b/command/views/operation_test.go similarity index 98% rename from internal/command/views/operation_test.go rename to command/views/operation_test.go index 39da8959037b..46c8a3b9bbda 100644 --- a/internal/command/views/operation_test.go +++ b/command/views/operation_test.go @@ -6,14 +6,14 @@ import ( "strings" "testing" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/lang/globalref" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/statefile" - "github.com/hashicorp/terraform/internal/terminal" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/lang/globalref" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/statefile" + "github.com/hashicorp/terraform/terminal" + "github.com/hashicorp/terraform/terraform" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/command/views/output.go b/command/views/output.go similarity index 97% rename from internal/command/views/output.go rename to command/views/output.go index 6545aaceec9b..e71734e2ccf3 100644 --- a/internal/command/views/output.go +++ b/command/views/output.go @@ -11,10 +11,10 @@ import ( "github.com/zclconf/go-cty/cty/convert" ctyjson "github.com/zclconf/go-cty/cty/json" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/repl" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/repl" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/tfdiags" ) // The Output view renders either one or all outputs, depending on whether or diff --git a/internal/command/views/output_test.go b/command/views/output_test.go similarity index 98% rename from internal/command/views/output_test.go rename to command/views/output_test.go index 3307778e673d..a57c59949fdd 100644 --- a/internal/command/views/output_test.go +++ b/command/views/output_test.go @@ -4,9 +4,9 @@ import ( "strings" "testing" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/terminal" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/terminal" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/command/views/plan.go b/command/views/plan.go similarity index 91% rename from internal/command/views/plan.go rename to command/views/plan.go index 8db4d3204c5e..56678f383375 100644 --- a/internal/command/views/plan.go +++ b/command/views/plan.go @@ -3,9 +3,9 @@ package views import ( "fmt" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" ) // The Plan view is used for the plan command. diff --git a/internal/command/views/plan_test.go b/command/views/plan_test.go similarity index 92% rename from internal/command/views/plan_test.go rename to command/views/plan_test.go index 33205738ad77..1fc56ade258f 100644 --- a/internal/command/views/plan_test.go +++ b/command/views/plan_test.go @@ -3,13 +3,13 @@ package views import ( "testing" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/terminal" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/terminal" + "github.com/hashicorp/terraform/terraform" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/command/views/refresh.go b/command/views/refresh.go similarity index 89% rename from internal/command/views/refresh.go rename to command/views/refresh.go index c670fd2d2727..39db5a3bf189 100644 --- a/internal/command/views/refresh.go +++ b/command/views/refresh.go @@ -3,11 +3,11 @@ package views import ( "fmt" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/views/json" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/views/json" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" ) // The Refresh view is used for the refresh command. diff --git a/internal/command/views/refresh_test.go b/command/views/refresh_test.go similarity index 92% rename from internal/command/views/refresh_test.go rename to command/views/refresh_test.go index d68348e5fca4..fc907a69c54f 100644 --- a/internal/command/views/refresh_test.go +++ b/command/views/refresh_test.go @@ -4,10 +4,10 @@ import ( "strings" "testing" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/lang/marks" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/terminal" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/lang/marks" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/terminal" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/command/views/show.go b/command/views/show.go similarity index 86% rename from internal/command/views/show.go rename to command/views/show.go index 4cd4e2b6707c..2cc629b7b33f 100644 --- a/internal/command/views/show.go +++ b/command/views/show.go @@ -3,16 +3,16 @@ package views import ( "fmt" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/jsonformat" - "github.com/hashicorp/terraform/internal/command/jsonplan" - "github.com/hashicorp/terraform/internal/command/jsonprovider" - "github.com/hashicorp/terraform/internal/command/jsonstate" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states/statefile" - "github.com/hashicorp/terraform/internal/terraform" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/jsonformat" + "github.com/hashicorp/terraform/command/jsonplan" + "github.com/hashicorp/terraform/command/jsonprovider" + "github.com/hashicorp/terraform/command/jsonstate" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/states/statefile" + "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/tfdiags" ) type Show interface { diff --git a/internal/command/views/show_test.go b/command/views/show_test.go similarity index 89% rename from internal/command/views/show_test.go rename to command/views/show_test.go index 29fff81ca259..14028c84d3a7 100644 --- a/internal/command/views/show_test.go +++ b/command/views/show_test.go @@ -5,15 +5,15 @@ import ( "strings" "testing" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/initwd" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/statefile" - "github.com/hashicorp/terraform/internal/terminal" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/initwd" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/statefile" + "github.com/hashicorp/terraform/terminal" + "github.com/hashicorp/terraform/terraform" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/command/views/state_locker.go b/command/views/state_locker.go similarity index 97% rename from internal/command/views/state_locker.go rename to command/views/state_locker.go index baa465f2933a..1c87600cf269 100644 --- a/internal/command/views/state_locker.go +++ b/command/views/state_locker.go @@ -5,7 +5,7 @@ import ( "fmt" "time" - "github.com/hashicorp/terraform/internal/command/arguments" + "github.com/hashicorp/terraform/command/arguments" ) // The StateLocker view is used to display locking/unlocking status messages diff --git a/internal/command/views/test.go b/command/views/test.go similarity index 97% rename from internal/command/views/test.go rename to command/views/test.go index 18c32c747b7b..f448bb968770 100644 --- a/internal/command/views/test.go +++ b/command/views/test.go @@ -7,11 +7,11 @@ import ( "sort" "strings" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/format" - "github.com/hashicorp/terraform/internal/moduletest" - "github.com/hashicorp/terraform/internal/terminal" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/format" + "github.com/hashicorp/terraform/moduletest" + "github.com/hashicorp/terraform/terminal" + "github.com/hashicorp/terraform/tfdiags" "github.com/mitchellh/colorstring" ) diff --git a/internal/command/views/test_test.go b/command/views/test_test.go similarity index 81% rename from internal/command/views/test_test.go rename to command/views/test_test.go index 6acd889e8551..144b3c3d24ae 100644 --- a/internal/command/views/test_test.go +++ b/command/views/test_test.go @@ -4,9 +4,9 @@ import ( "strings" "testing" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/moduletest" - "github.com/hashicorp/terraform/internal/terminal" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/moduletest" + "github.com/hashicorp/terraform/terminal" ) func TestTest(t *testing.T) { diff --git a/internal/command/views/testdata/show/main.tf b/command/views/testdata/show/main.tf similarity index 100% rename from internal/command/views/testdata/show/main.tf rename to command/views/testdata/show/main.tf diff --git a/internal/command/views/validate.go b/command/views/validate.go similarity index 94% rename from internal/command/views/validate.go rename to command/views/validate.go index 08ce913f82ce..b04180f3347b 100644 --- a/internal/command/views/validate.go +++ b/command/views/validate.go @@ -4,10 +4,10 @@ import ( "encoding/json" "fmt" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/format" - viewsjson "github.com/hashicorp/terraform/internal/command/views/json" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/format" + viewsjson "github.com/hashicorp/terraform/command/views/json" + "github.com/hashicorp/terraform/tfdiags" ) // The Validate is used for the validate command. diff --git a/internal/command/views/validate_test.go b/command/views/validate_test.go similarity index 94% rename from internal/command/views/validate_test.go rename to command/views/validate_test.go index 6545c3b3140f..44744be7268a 100644 --- a/internal/command/views/validate_test.go +++ b/command/views/validate_test.go @@ -5,9 +5,9 @@ import ( "strings" "testing" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/terminal" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/terminal" + "github.com/hashicorp/terraform/tfdiags" ) func TestValidateHuman(t *testing.T) { diff --git a/internal/command/views/view.go b/command/views/view.go similarity index 95% rename from internal/command/views/view.go rename to command/views/view.go index 206ead7fd5c1..c70eb208da78 100644 --- a/internal/command/views/view.go +++ b/command/views/view.go @@ -1,10 +1,10 @@ package views import ( - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/format" - "github.com/hashicorp/terraform/internal/terminal" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/format" + "github.com/hashicorp/terraform/terminal" + "github.com/hashicorp/terraform/tfdiags" "github.com/mitchellh/colorstring" ) diff --git a/internal/command/webbrowser/mock.go b/command/webbrowser/mock.go similarity index 99% rename from internal/command/webbrowser/mock.go rename to command/webbrowser/mock.go index 1245cbedeb05..ef411ba1e579 100644 --- a/internal/command/webbrowser/mock.go +++ b/command/webbrowser/mock.go @@ -8,7 +8,7 @@ import ( "net/url" "sync" - "github.com/hashicorp/terraform/internal/httpclient" + "github.com/hashicorp/terraform/httpclient" ) // NewMockLauncher creates and returns a mock implementation of Launcher, diff --git a/internal/command/webbrowser/mock_test.go b/command/webbrowser/mock_test.go similarity index 100% rename from internal/command/webbrowser/mock_test.go rename to command/webbrowser/mock_test.go diff --git a/internal/command/webbrowser/native.go b/command/webbrowser/native.go similarity index 100% rename from internal/command/webbrowser/native.go rename to command/webbrowser/native.go diff --git a/internal/command/webbrowser/webbrowser.go b/command/webbrowser/webbrowser.go similarity index 100% rename from internal/command/webbrowser/webbrowser.go rename to command/webbrowser/webbrowser.go diff --git a/internal/command/workdir/dir.go b/command/workdir/dir.go similarity index 100% rename from internal/command/workdir/dir.go rename to command/workdir/dir.go diff --git a/internal/command/workdir/doc.go b/command/workdir/doc.go similarity index 100% rename from internal/command/workdir/doc.go rename to command/workdir/doc.go diff --git a/internal/command/workdir/normalize_path.go b/command/workdir/normalize_path.go similarity index 100% rename from internal/command/workdir/normalize_path.go rename to command/workdir/normalize_path.go diff --git a/internal/command/workdir/plugin_dirs.go b/command/workdir/plugin_dirs.go similarity index 100% rename from internal/command/workdir/plugin_dirs.go rename to command/workdir/plugin_dirs.go diff --git a/internal/command/workdir/plugin_dirs_test.go b/command/workdir/plugin_dirs_test.go similarity index 100% rename from internal/command/workdir/plugin_dirs_test.go rename to command/workdir/plugin_dirs_test.go diff --git a/internal/command/workspace_command.go b/command/workspace_command.go similarity index 100% rename from internal/command/workspace_command.go rename to command/workspace_command.go diff --git a/internal/command/workspace_command_test.go b/command/workspace_command_test.go similarity index 96% rename from internal/command/workspace_command_test.go rename to command/workspace_command_test.go index 7d2052e111d7..9f11f6d21a8e 100644 --- a/internal/command/workspace_command_test.go +++ b/command/workspace_command_test.go @@ -7,15 +7,15 @@ import ( "strings" "testing" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/backend" - "github.com/hashicorp/terraform/internal/backend/local" - "github.com/hashicorp/terraform/internal/backend/remote-state/inmem" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/backend/local" + "github.com/hashicorp/terraform/backend/remote-state/inmem" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/statemgr" "github.com/mitchellh/cli" - legacy "github.com/hashicorp/terraform/internal/legacy/terraform" + legacy "github.com/hashicorp/terraform/legacy/terraform" ) func TestWorkspace_createAndChange(t *testing.T) { diff --git a/internal/command/workspace_delete.go b/command/workspace_delete.go similarity index 95% rename from internal/command/workspace_delete.go rename to command/workspace_delete.go index f59852d5d7c2..afe265d326ce 100644 --- a/internal/command/workspace_delete.go +++ b/command/workspace_delete.go @@ -5,11 +5,11 @@ import ( "strings" "time" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/clistate" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/clistate" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/tfdiags" "github.com/mitchellh/cli" "github.com/posener/complete" ) diff --git a/internal/command/workspace_list.go b/command/workspace_list.go similarity index 97% rename from internal/command/workspace_list.go rename to command/workspace_list.go index 7b43bc34627d..40f7d426d719 100644 --- a/internal/command/workspace_list.go +++ b/command/workspace_list.go @@ -5,7 +5,7 @@ import ( "fmt" "strings" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" "github.com/posener/complete" ) diff --git a/internal/command/workspace_new.go b/command/workspace_new.go similarity index 94% rename from internal/command/workspace_new.go rename to command/workspace_new.go index 38985622079f..de254c1f5c1d 100644 --- a/internal/command/workspace_new.go +++ b/command/workspace_new.go @@ -6,11 +6,11 @@ import ( "strings" "time" - "github.com/hashicorp/terraform/internal/command/arguments" - "github.com/hashicorp/terraform/internal/command/clistate" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/states/statefile" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/command/arguments" + "github.com/hashicorp/terraform/command/clistate" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/states/statefile" + "github.com/hashicorp/terraform/tfdiags" "github.com/mitchellh/cli" "github.com/posener/complete" ) diff --git a/internal/command/workspace_select.go b/command/workspace_select.go similarity index 98% rename from internal/command/workspace_select.go rename to command/workspace_select.go index 7dd7fc7e6d9a..791e01ade39f 100644 --- a/internal/command/workspace_select.go +++ b/command/workspace_select.go @@ -4,7 +4,7 @@ import ( "fmt" "strings" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" "github.com/mitchellh/cli" "github.com/posener/complete" ) diff --git a/internal/command/workspace_show.go b/command/workspace_show.go similarity index 100% rename from internal/command/workspace_show.go rename to command/workspace_show.go diff --git a/commands.go b/commands.go index aadfc51b3114..cb18b95d4a1f 100644 --- a/commands.go +++ b/commands.go @@ -10,14 +10,14 @@ import ( svchost "github.com/hashicorp/terraform-svchost" "github.com/hashicorp/terraform-svchost/auth" "github.com/hashicorp/terraform-svchost/disco" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/command" - "github.com/hashicorp/terraform/internal/command/cliconfig" - "github.com/hashicorp/terraform/internal/command/views" - "github.com/hashicorp/terraform/internal/command/webbrowser" - "github.com/hashicorp/terraform/internal/getproviders" - pluginDiscovery "github.com/hashicorp/terraform/internal/plugin/discovery" - "github.com/hashicorp/terraform/internal/terminal" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/command" + "github.com/hashicorp/terraform/command/cliconfig" + "github.com/hashicorp/terraform/command/views" + "github.com/hashicorp/terraform/command/webbrowser" + "github.com/hashicorp/terraform/getproviders" + pluginDiscovery "github.com/hashicorp/terraform/plugin/discovery" + "github.com/hashicorp/terraform/terminal" ) // runningInAutomationEnvName gives the name of an environment variable that diff --git a/internal/communicator/communicator.go b/communicator/communicator.go similarity index 92% rename from internal/communicator/communicator.go rename to communicator/communicator.go index 5b754b34f323..2908da18a0c7 100644 --- a/internal/communicator/communicator.go +++ b/communicator/communicator.go @@ -9,11 +9,11 @@ import ( "sync/atomic" "time" - "github.com/hashicorp/terraform/internal/communicator/remote" - "github.com/hashicorp/terraform/internal/communicator/shared" - "github.com/hashicorp/terraform/internal/communicator/ssh" - "github.com/hashicorp/terraform/internal/communicator/winrm" - "github.com/hashicorp/terraform/internal/provisioners" + "github.com/hashicorp/terraform/communicator/remote" + "github.com/hashicorp/terraform/communicator/shared" + "github.com/hashicorp/terraform/communicator/ssh" + "github.com/hashicorp/terraform/communicator/winrm" + "github.com/hashicorp/terraform/provisioners" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/communicator/communicator_mock.go b/communicator/communicator_mock.go similarity index 95% rename from internal/communicator/communicator_mock.go rename to communicator/communicator_mock.go index b60edec19721..b619560c0cab 100644 --- a/internal/communicator/communicator_mock.go +++ b/communicator/communicator_mock.go @@ -7,8 +7,8 @@ import ( "strings" "time" - "github.com/hashicorp/terraform/internal/communicator/remote" - "github.com/hashicorp/terraform/internal/provisioners" + "github.com/hashicorp/terraform/communicator/remote" + "github.com/hashicorp/terraform/provisioners" ) // MockCommunicator is an implementation of Communicator that can be used for tests. diff --git a/internal/communicator/communicator_test.go b/communicator/communicator_test.go similarity index 100% rename from internal/communicator/communicator_test.go rename to communicator/communicator_test.go diff --git a/internal/communicator/remote/command.go b/communicator/remote/command.go similarity index 100% rename from internal/communicator/remote/command.go rename to communicator/remote/command.go diff --git a/internal/communicator/remote/command_test.go b/communicator/remote/command_test.go similarity index 100% rename from internal/communicator/remote/command_test.go rename to communicator/remote/command_test.go diff --git a/internal/communicator/shared/shared.go b/communicator/shared/shared.go similarity index 98% rename from internal/communicator/shared/shared.go rename to communicator/shared/shared.go index 5990807a7809..a9bb22b45cb2 100644 --- a/internal/communicator/shared/shared.go +++ b/communicator/shared/shared.go @@ -4,7 +4,7 @@ import ( "fmt" "net" - "github.com/hashicorp/terraform/internal/configs/configschema" + "github.com/hashicorp/terraform/configs/configschema" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/communicator/shared/shared_test.go b/communicator/shared/shared_test.go similarity index 100% rename from internal/communicator/shared/shared_test.go rename to communicator/shared/shared_test.go diff --git a/internal/communicator/ssh/communicator.go b/communicator/ssh/communicator.go similarity index 99% rename from internal/communicator/ssh/communicator.go rename to communicator/ssh/communicator.go index 609dc1fbaf0e..c1bd364aa9fd 100644 --- a/internal/communicator/ssh/communicator.go +++ b/communicator/ssh/communicator.go @@ -19,13 +19,13 @@ import ( "time" "github.com/apparentlymart/go-shquot/shquot" - "github.com/hashicorp/terraform/internal/communicator/remote" - "github.com/hashicorp/terraform/internal/provisioners" + "github.com/hashicorp/terraform/communicator/remote" + "github.com/hashicorp/terraform/provisioners" "github.com/zclconf/go-cty/cty" "golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh/agent" - _ "github.com/hashicorp/terraform/internal/logging" + _ "github.com/hashicorp/terraform/logging" ) const ( diff --git a/internal/communicator/ssh/communicator_test.go b/communicator/ssh/communicator_test.go similarity index 99% rename from internal/communicator/ssh/communicator_test.go rename to communicator/ssh/communicator_test.go index b829e5b9afb3..ac2527966ed2 100644 --- a/internal/communicator/ssh/communicator_test.go +++ b/communicator/ssh/communicator_test.go @@ -20,7 +20,7 @@ import ( "testing" "time" - "github.com/hashicorp/terraform/internal/communicator/remote" + "github.com/hashicorp/terraform/communicator/remote" "github.com/zclconf/go-cty/cty" "golang.org/x/crypto/ssh" ) diff --git a/internal/communicator/ssh/http_proxy.go b/communicator/ssh/http_proxy.go similarity index 100% rename from internal/communicator/ssh/http_proxy.go rename to communicator/ssh/http_proxy.go diff --git a/internal/communicator/ssh/password.go b/communicator/ssh/password.go similarity index 100% rename from internal/communicator/ssh/password.go rename to communicator/ssh/password.go diff --git a/internal/communicator/ssh/password_test.go b/communicator/ssh/password_test.go similarity index 100% rename from internal/communicator/ssh/password_test.go rename to communicator/ssh/password_test.go diff --git a/internal/communicator/ssh/provisioner.go b/communicator/ssh/provisioner.go similarity index 99% rename from internal/communicator/ssh/provisioner.go rename to communicator/ssh/provisioner.go index b98ee9f5d2cb..a7ec6862ed61 100644 --- a/internal/communicator/ssh/provisioner.go +++ b/communicator/ssh/provisioner.go @@ -13,7 +13,7 @@ import ( "strings" "time" - "github.com/hashicorp/terraform/internal/communicator/shared" + "github.com/hashicorp/terraform/communicator/shared" sshagent "github.com/xanzy/ssh-agent" "github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty/gocty" diff --git a/internal/communicator/ssh/provisioner_test.go b/communicator/ssh/provisioner_test.go similarity index 100% rename from internal/communicator/ssh/provisioner_test.go rename to communicator/ssh/provisioner_test.go diff --git a/internal/communicator/ssh/ssh_test.go b/communicator/ssh/ssh_test.go similarity index 100% rename from internal/communicator/ssh/ssh_test.go rename to communicator/ssh/ssh_test.go diff --git a/internal/communicator/winrm/communicator.go b/communicator/winrm/communicator.go similarity index 97% rename from internal/communicator/winrm/communicator.go rename to communicator/winrm/communicator.go index 302ccec8eba1..d877e3065f2d 100644 --- a/internal/communicator/winrm/communicator.go +++ b/communicator/winrm/communicator.go @@ -9,8 +9,8 @@ import ( "strings" "time" - "github.com/hashicorp/terraform/internal/communicator/remote" - "github.com/hashicorp/terraform/internal/provisioners" + "github.com/hashicorp/terraform/communicator/remote" + "github.com/hashicorp/terraform/provisioners" "github.com/masterzen/winrm" "github.com/packer-community/winrmcp/winrmcp" "github.com/zclconf/go-cty/cty" diff --git a/internal/communicator/winrm/communicator_test.go b/communicator/winrm/communicator_test.go similarity index 97% rename from internal/communicator/winrm/communicator_test.go rename to communicator/winrm/communicator_test.go index bc1de8e30913..bd8d2ecd5421 100644 --- a/internal/communicator/winrm/communicator_test.go +++ b/communicator/winrm/communicator_test.go @@ -8,8 +8,8 @@ import ( "testing" "github.com/dylanmei/winrmtest" - "github.com/hashicorp/terraform/internal/communicator/remote" - "github.com/hashicorp/terraform/internal/communicator/shared" + "github.com/hashicorp/terraform/communicator/remote" + "github.com/hashicorp/terraform/communicator/shared" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/communicator/winrm/provisioner.go b/communicator/winrm/provisioner.go similarity index 98% rename from internal/communicator/winrm/provisioner.go rename to communicator/winrm/provisioner.go index 3843c9d00e1b..f77918ec8733 100644 --- a/internal/communicator/winrm/provisioner.go +++ b/communicator/winrm/provisioner.go @@ -7,7 +7,7 @@ import ( "strings" "time" - "github.com/hashicorp/terraform/internal/communicator/shared" + "github.com/hashicorp/terraform/communicator/shared" "github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty/gocty" ) diff --git a/internal/communicator/winrm/provisioner_test.go b/communicator/winrm/provisioner_test.go similarity index 100% rename from internal/communicator/winrm/provisioner_test.go rename to communicator/winrm/provisioner_test.go diff --git a/internal/configs/backend.go b/configs/backend.go similarity index 95% rename from internal/configs/backend.go rename to configs/backend.go index 4bf968e6ad7d..5d8b9732a8d4 100644 --- a/internal/configs/backend.go +++ b/configs/backend.go @@ -3,7 +3,7 @@ package configs import ( "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hcldec" - "github.com/hashicorp/terraform/internal/configs/configschema" + "github.com/hashicorp/terraform/configs/configschema" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/configs/checks.go b/configs/checks.go similarity index 97% rename from internal/configs/checks.go rename to configs/checks.go index 417dff45eece..822141058138 100644 --- a/internal/configs/checks.go +++ b/configs/checks.go @@ -4,8 +4,8 @@ import ( "fmt" "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/lang" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/lang" ) // CheckRule represents a configuration-defined validation rule, precondition, diff --git a/internal/configs/cloud.go b/configs/cloud.go similarity index 100% rename from internal/configs/cloud.go rename to configs/cloud.go diff --git a/internal/configs/compat_shim.go b/configs/compat_shim.go similarity index 100% rename from internal/configs/compat_shim.go rename to configs/compat_shim.go diff --git a/internal/configs/config.go b/configs/config.go similarity index 99% rename from internal/configs/config.go rename to configs/config.go index f38d3cd85daa..1b654e0d2b44 100644 --- a/internal/configs/config.go +++ b/configs/config.go @@ -7,9 +7,9 @@ import ( version "github.com/hashicorp/go-version" "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/depsfile" - "github.com/hashicorp/terraform/internal/getproviders" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/depsfile" + "github.com/hashicorp/terraform/getproviders" ) // A Config is a node in the tree of modules within a configuration. diff --git a/internal/configs/config_build.go b/configs/config_build.go similarity index 99% rename from internal/configs/config_build.go rename to configs/config_build.go index 4e2dddaa1b06..d33ec99fdc5f 100644 --- a/internal/configs/config_build.go +++ b/configs/config_build.go @@ -5,7 +5,7 @@ import ( version "github.com/hashicorp/go-version" "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) // BuildConfig constructs a Config from a root module by loading all of its diff --git a/internal/configs/config_build_test.go b/configs/config_build_test.go similarity index 100% rename from internal/configs/config_build_test.go rename to configs/config_build_test.go diff --git a/internal/configs/config_test.go b/configs/config_test.go similarity index 99% rename from internal/configs/config_test.go rename to configs/config_test.go index b5360278df7b..e5b4de5cf0e9 100644 --- a/internal/configs/config_test.go +++ b/configs/config_test.go @@ -11,9 +11,9 @@ import ( version "github.com/hashicorp/go-version" "github.com/hashicorp/hcl/v2/hclsyntax" svchost "github.com/hashicorp/terraform-svchost" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/depsfile" - "github.com/hashicorp/terraform/internal/getproviders" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/depsfile" + "github.com/hashicorp/terraform/getproviders" ) func TestConfigProviderTypes(t *testing.T) { diff --git a/internal/configs/configload/copy_dir.go b/configs/configload/copy_dir.go similarity index 100% rename from internal/configs/configload/copy_dir.go rename to configs/configload/copy_dir.go diff --git a/internal/configs/configload/copy_dir_test.go b/configs/configload/copy_dir_test.go similarity index 100% rename from internal/configs/configload/copy_dir_test.go rename to configs/configload/copy_dir_test.go diff --git a/internal/configs/configload/doc.go b/configs/configload/doc.go similarity index 100% rename from internal/configs/configload/doc.go rename to configs/configload/doc.go diff --git a/internal/configs/configload/inode.go b/configs/configload/inode.go similarity index 100% rename from internal/configs/configload/inode.go rename to configs/configload/inode.go diff --git a/internal/configs/configload/inode_freebsd.go b/configs/configload/inode_freebsd.go similarity index 100% rename from internal/configs/configload/inode_freebsd.go rename to configs/configload/inode_freebsd.go diff --git a/internal/configs/configload/inode_windows.go b/configs/configload/inode_windows.go similarity index 100% rename from internal/configs/configload/inode_windows.go rename to configs/configload/inode_windows.go diff --git a/internal/configs/configload/loader.go b/configs/configload/loader.go similarity index 98% rename from internal/configs/configload/loader.go rename to configs/configload/loader.go index 0f2481d3f611..72f89bbe8ae6 100644 --- a/internal/configs/configload/loader.go +++ b/configs/configload/loader.go @@ -5,8 +5,8 @@ import ( "path/filepath" "github.com/hashicorp/terraform-svchost/disco" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/registry" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/registry" "github.com/spf13/afero" ) diff --git a/internal/configs/configload/loader_load.go b/configs/configload/loader_load.go similarity index 98% rename from internal/configs/configload/loader_load.go rename to configs/configload/loader_load.go index 1ca26814a273..b14a3aed4423 100644 --- a/internal/configs/configload/loader_load.go +++ b/configs/configload/loader_load.go @@ -5,7 +5,7 @@ import ( version "github.com/hashicorp/go-version" "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/configs" + "github.com/hashicorp/terraform/configs" ) // LoadConfig reads the Terraform module in the given directory and uses it as the diff --git a/internal/configs/configload/loader_load_test.go b/configs/configload/loader_load_test.go similarity index 99% rename from internal/configs/configload/loader_load_test.go rename to configs/configload/loader_load_test.go index d285cc9f1656..b90f7a8e902f 100644 --- a/internal/configs/configload/loader_load_test.go +++ b/configs/configload/loader_load_test.go @@ -10,7 +10,7 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/configs" + "github.com/hashicorp/terraform/configs" ) func TestLoaderLoadConfig_okay(t *testing.T) { diff --git a/internal/configs/configload/loader_snapshot.go b/configs/configload/loader_snapshot.go similarity index 99% rename from internal/configs/configload/loader_snapshot.go rename to configs/configload/loader_snapshot.go index 915665f833ba..51b428f9e563 100644 --- a/internal/configs/configload/loader_snapshot.go +++ b/configs/configload/loader_snapshot.go @@ -10,8 +10,8 @@ import ( version "github.com/hashicorp/go-version" "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/modsdir" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/modsdir" "github.com/spf13/afero" ) diff --git a/internal/configs/configload/loader_snapshot_test.go b/configs/configload/loader_snapshot_test.go similarity index 100% rename from internal/configs/configload/loader_snapshot_test.go rename to configs/configload/loader_snapshot_test.go diff --git a/internal/configs/configload/loader_test.go b/configs/configload/loader_test.go similarity index 100% rename from internal/configs/configload/loader_test.go rename to configs/configload/loader_test.go diff --git a/internal/configs/configload/module_mgr.go b/configs/configload/module_mgr.go similarity index 94% rename from internal/configs/configload/module_mgr.go rename to configs/configload/module_mgr.go index bf8d067e6d23..314043bfebbd 100644 --- a/internal/configs/configload/module_mgr.go +++ b/configs/configload/module_mgr.go @@ -5,8 +5,8 @@ import ( "path/filepath" "github.com/hashicorp/terraform-svchost/disco" - "github.com/hashicorp/terraform/internal/modsdir" - "github.com/hashicorp/terraform/internal/registry" + "github.com/hashicorp/terraform/modsdir" + "github.com/hashicorp/terraform/registry" "github.com/spf13/afero" ) diff --git a/internal/configs/configload/testdata/add-version-constraint/.terraform/modules/child/empty.tf b/configs/configload/testdata/add-version-constraint/.terraform/modules/child/empty.tf similarity index 100% rename from internal/configs/configload/testdata/add-version-constraint/.terraform/modules/child/empty.tf rename to configs/configload/testdata/add-version-constraint/.terraform/modules/child/empty.tf diff --git a/internal/configs/configload/testdata/add-version-constraint/.terraform/modules/modules.json b/configs/configload/testdata/add-version-constraint/.terraform/modules/modules.json similarity index 100% rename from internal/configs/configload/testdata/add-version-constraint/.terraform/modules/modules.json rename to configs/configload/testdata/add-version-constraint/.terraform/modules/modules.json diff --git a/internal/configs/configload/testdata/add-version-constraint/add-version-constraint.tf b/configs/configload/testdata/add-version-constraint/add-version-constraint.tf similarity index 100% rename from internal/configs/configload/testdata/add-version-constraint/add-version-constraint.tf rename to configs/configload/testdata/add-version-constraint/add-version-constraint.tf diff --git a/internal/configs/configload/testdata/already-installed-now-invalid/.terraform/modules/modules.json b/configs/configload/testdata/already-installed-now-invalid/.terraform/modules/modules.json similarity index 100% rename from internal/configs/configload/testdata/already-installed-now-invalid/.terraform/modules/modules.json rename to configs/configload/testdata/already-installed-now-invalid/.terraform/modules/modules.json diff --git a/internal/configs/configload/testdata/already-installed-now-invalid/foo/bar/main.tf b/configs/configload/testdata/already-installed-now-invalid/foo/bar/main.tf similarity index 100% rename from internal/configs/configload/testdata/already-installed-now-invalid/foo/bar/main.tf rename to configs/configload/testdata/already-installed-now-invalid/foo/bar/main.tf diff --git a/internal/configs/configload/testdata/already-installed-now-invalid/foo/main.tf b/configs/configload/testdata/already-installed-now-invalid/foo/main.tf similarity index 100% rename from internal/configs/configload/testdata/already-installed-now-invalid/foo/main.tf rename to configs/configload/testdata/already-installed-now-invalid/foo/main.tf diff --git a/internal/configs/configload/testdata/already-installed-now-invalid/root.tf b/configs/configload/testdata/already-installed-now-invalid/root.tf similarity index 100% rename from internal/configs/configload/testdata/already-installed-now-invalid/root.tf rename to configs/configload/testdata/already-installed-now-invalid/root.tf diff --git a/internal/configs/configload/testdata/already-installed/.terraform/modules/child_a/child_a.tf b/configs/configload/testdata/already-installed/.terraform/modules/child_a/child_a.tf similarity index 100% rename from internal/configs/configload/testdata/already-installed/.terraform/modules/child_a/child_a.tf rename to configs/configload/testdata/already-installed/.terraform/modules/child_a/child_a.tf diff --git a/internal/configs/configload/testdata/already-installed/.terraform/modules/child_a/child_c/child_c.tf b/configs/configload/testdata/already-installed/.terraform/modules/child_a/child_c/child_c.tf similarity index 100% rename from internal/configs/configload/testdata/already-installed/.terraform/modules/child_a/child_c/child_c.tf rename to configs/configload/testdata/already-installed/.terraform/modules/child_a/child_c/child_c.tf diff --git a/internal/configs/configload/testdata/already-installed/.terraform/modules/child_b.child_d/child_d.tf b/configs/configload/testdata/already-installed/.terraform/modules/child_b.child_d/child_d.tf similarity index 100% rename from internal/configs/configload/testdata/already-installed/.terraform/modules/child_b.child_d/child_d.tf rename to configs/configload/testdata/already-installed/.terraform/modules/child_b.child_d/child_d.tf diff --git a/internal/configs/configload/testdata/already-installed/.terraform/modules/child_b/child_b.tf b/configs/configload/testdata/already-installed/.terraform/modules/child_b/child_b.tf similarity index 100% rename from internal/configs/configload/testdata/already-installed/.terraform/modules/child_b/child_b.tf rename to configs/configload/testdata/already-installed/.terraform/modules/child_b/child_b.tf diff --git a/internal/configs/configload/testdata/already-installed/.terraform/modules/modules.json b/configs/configload/testdata/already-installed/.terraform/modules/modules.json similarity index 100% rename from internal/configs/configload/testdata/already-installed/.terraform/modules/modules.json rename to configs/configload/testdata/already-installed/.terraform/modules/modules.json diff --git a/internal/configs/configload/testdata/already-installed/root.tf b/configs/configload/testdata/already-installed/root.tf similarity index 100% rename from internal/configs/configload/testdata/already-installed/root.tf rename to configs/configload/testdata/already-installed/root.tf diff --git a/internal/configs/configload/testdata/child-provider-child-count/.terraform/modules/modules.json b/configs/configload/testdata/child-provider-child-count/.terraform/modules/modules.json similarity index 100% rename from internal/configs/configload/testdata/child-provider-child-count/.terraform/modules/modules.json rename to configs/configload/testdata/child-provider-child-count/.terraform/modules/modules.json diff --git a/internal/configs/configload/testdata/child-provider-child-count/child-provider-child-count.tf b/configs/configload/testdata/child-provider-child-count/child-provider-child-count.tf similarity index 100% rename from internal/configs/configload/testdata/child-provider-child-count/child-provider-child-count.tf rename to configs/configload/testdata/child-provider-child-count/child-provider-child-count.tf diff --git a/internal/configs/configload/testdata/child-provider-child-count/child/child-provider-child-count-child.tf b/configs/configload/testdata/child-provider-child-count/child/child-provider-child-count-child.tf similarity index 100% rename from internal/configs/configload/testdata/child-provider-child-count/child/child-provider-child-count-child.tf rename to configs/configload/testdata/child-provider-child-count/child/child-provider-child-count-child.tf diff --git a/internal/configs/configload/testdata/child-provider-child-count/grandchild/child-provider-child-count-grandchild.tf b/configs/configload/testdata/child-provider-child-count/grandchild/child-provider-child-count-grandchild.tf similarity index 100% rename from internal/configs/configload/testdata/child-provider-child-count/grandchild/child-provider-child-count-grandchild.tf rename to configs/configload/testdata/child-provider-child-count/grandchild/child-provider-child-count-grandchild.tf diff --git a/internal/configs/configload/testdata/child-provider-grandchild-count/.terraform/modules/modules.json b/configs/configload/testdata/child-provider-grandchild-count/.terraform/modules/modules.json similarity index 100% rename from internal/configs/configload/testdata/child-provider-grandchild-count/.terraform/modules/modules.json rename to configs/configload/testdata/child-provider-grandchild-count/.terraform/modules/modules.json diff --git a/internal/configs/configload/testdata/child-provider-grandchild-count/child-provider-grandchild-count.tf b/configs/configload/testdata/child-provider-grandchild-count/child-provider-grandchild-count.tf similarity index 100% rename from internal/configs/configload/testdata/child-provider-grandchild-count/child-provider-grandchild-count.tf rename to configs/configload/testdata/child-provider-grandchild-count/child-provider-grandchild-count.tf diff --git a/internal/configs/configload/testdata/child-provider-grandchild-count/child/child-provider-grandchild-count-child.tf b/configs/configload/testdata/child-provider-grandchild-count/child/child-provider-grandchild-count-child.tf similarity index 100% rename from internal/configs/configload/testdata/child-provider-grandchild-count/child/child-provider-grandchild-count-child.tf rename to configs/configload/testdata/child-provider-grandchild-count/child/child-provider-grandchild-count-child.tf diff --git a/internal/configs/configload/testdata/child-provider-grandchild-count/grandchild/child-provider-grandchild-count-grandchild.tf b/configs/configload/testdata/child-provider-grandchild-count/grandchild/child-provider-grandchild-count-grandchild.tf similarity index 100% rename from internal/configs/configload/testdata/child-provider-grandchild-count/grandchild/child-provider-grandchild-count-grandchild.tf rename to configs/configload/testdata/child-provider-grandchild-count/grandchild/child-provider-grandchild-count-grandchild.tf diff --git a/internal/configs/configload/testdata/empty/.gitignore b/configs/configload/testdata/empty/.gitignore similarity index 100% rename from internal/configs/configload/testdata/empty/.gitignore rename to configs/configload/testdata/empty/.gitignore diff --git a/internal/configs/configload/testdata/go-getter-modules/.gitignore b/configs/configload/testdata/go-getter-modules/.gitignore similarity index 100% rename from internal/configs/configload/testdata/go-getter-modules/.gitignore rename to configs/configload/testdata/go-getter-modules/.gitignore diff --git a/internal/configs/configload/testdata/go-getter-modules/root.tf b/configs/configload/testdata/go-getter-modules/root.tf similarity index 100% rename from internal/configs/configload/testdata/go-getter-modules/root.tf rename to configs/configload/testdata/go-getter-modules/root.tf diff --git a/internal/configs/configload/testdata/invalid-names-in-submodules/.terraform/modules/modules.json b/configs/configload/testdata/invalid-names-in-submodules/.terraform/modules/modules.json similarity index 100% rename from internal/configs/configload/testdata/invalid-names-in-submodules/.terraform/modules/modules.json rename to configs/configload/testdata/invalid-names-in-submodules/.terraform/modules/modules.json diff --git a/internal/configs/configload/testdata/invalid-names-in-submodules/main.tf b/configs/configload/testdata/invalid-names-in-submodules/main.tf similarity index 100% rename from internal/configs/configload/testdata/invalid-names-in-submodules/main.tf rename to configs/configload/testdata/invalid-names-in-submodules/main.tf diff --git a/internal/configs/configload/testdata/invalid-names-in-submodules/sub/main.tf b/configs/configload/testdata/invalid-names-in-submodules/sub/main.tf similarity index 100% rename from internal/configs/configload/testdata/invalid-names-in-submodules/sub/main.tf rename to configs/configload/testdata/invalid-names-in-submodules/sub/main.tf diff --git a/internal/configs/configload/testdata/invalid-names/main.tf b/configs/configload/testdata/invalid-names/main.tf similarity index 100% rename from internal/configs/configload/testdata/invalid-names/main.tf rename to configs/configload/testdata/invalid-names/main.tf diff --git a/internal/configs/configload/testdata/local-modules/child_a/child_a.tf b/configs/configload/testdata/local-modules/child_a/child_a.tf similarity index 100% rename from internal/configs/configload/testdata/local-modules/child_a/child_a.tf rename to configs/configload/testdata/local-modules/child_a/child_a.tf diff --git a/internal/configs/configload/testdata/local-modules/child_a/child_b/child_b.tf b/configs/configload/testdata/local-modules/child_a/child_b/child_b.tf similarity index 100% rename from internal/configs/configload/testdata/local-modules/child_a/child_b/child_b.tf rename to configs/configload/testdata/local-modules/child_a/child_b/child_b.tf diff --git a/internal/configs/configload/testdata/local-modules/root.tf b/configs/configload/testdata/local-modules/root.tf similarity index 100% rename from internal/configs/configload/testdata/local-modules/root.tf rename to configs/configload/testdata/local-modules/root.tf diff --git a/internal/configs/configload/testdata/module-depends-on/.terraform/modules/modules.json b/configs/configload/testdata/module-depends-on/.terraform/modules/modules.json similarity index 100% rename from internal/configs/configload/testdata/module-depends-on/.terraform/modules/modules.json rename to configs/configload/testdata/module-depends-on/.terraform/modules/modules.json diff --git a/internal/configs/configload/testdata/module-depends-on/child/main.tf b/configs/configload/testdata/module-depends-on/child/main.tf similarity index 100% rename from internal/configs/configload/testdata/module-depends-on/child/main.tf rename to configs/configload/testdata/module-depends-on/child/main.tf diff --git a/internal/configs/configload/testdata/module-depends-on/child2/main.tf b/configs/configload/testdata/module-depends-on/child2/main.tf similarity index 100% rename from internal/configs/configload/testdata/module-depends-on/child2/main.tf rename to configs/configload/testdata/module-depends-on/child2/main.tf diff --git a/internal/configs/configload/testdata/module-depends-on/root.tf b/configs/configload/testdata/module-depends-on/root.tf similarity index 100% rename from internal/configs/configload/testdata/module-depends-on/root.tf rename to configs/configload/testdata/module-depends-on/root.tf diff --git a/internal/configs/configload/testdata/registry-modules/.gitignore b/configs/configload/testdata/registry-modules/.gitignore similarity index 100% rename from internal/configs/configload/testdata/registry-modules/.gitignore rename to configs/configload/testdata/registry-modules/.gitignore diff --git a/internal/configs/configload/testdata/registry-modules/root.tf b/configs/configload/testdata/registry-modules/root.tf similarity index 100% rename from internal/configs/configload/testdata/registry-modules/root.tf rename to configs/configload/testdata/registry-modules/root.tf diff --git a/internal/configs/configload/testing.go b/configs/configload/testing.go similarity index 100% rename from internal/configs/configload/testing.go rename to configs/configload/testing.go diff --git a/internal/configs/configschema/coerce_value.go b/configs/configschema/coerce_value.go similarity index 100% rename from internal/configs/configschema/coerce_value.go rename to configs/configschema/coerce_value.go diff --git a/internal/configs/configschema/coerce_value_test.go b/configs/configschema/coerce_value_test.go similarity index 99% rename from internal/configs/configschema/coerce_value_test.go rename to configs/configschema/coerce_value_test.go index 37f81b76986f..d682a0ed0be3 100644 --- a/internal/configs/configschema/coerce_value_test.go +++ b/configs/configschema/coerce_value_test.go @@ -5,7 +5,7 @@ import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" ) func TestCoerceValue(t *testing.T) { diff --git a/internal/configs/configschema/decoder_spec.go b/configs/configschema/decoder_spec.go similarity index 100% rename from internal/configs/configschema/decoder_spec.go rename to configs/configschema/decoder_spec.go diff --git a/internal/configs/configschema/decoder_spec_test.go b/configs/configschema/decoder_spec_test.go similarity index 100% rename from internal/configs/configschema/decoder_spec_test.go rename to configs/configschema/decoder_spec_test.go diff --git a/internal/configs/configschema/doc.go b/configs/configschema/doc.go similarity index 100% rename from internal/configs/configschema/doc.go rename to configs/configschema/doc.go diff --git a/internal/configs/configschema/empty_value.go b/configs/configschema/empty_value.go similarity index 100% rename from internal/configs/configschema/empty_value.go rename to configs/configschema/empty_value.go diff --git a/internal/configs/configschema/empty_value_test.go b/configs/configschema/empty_value_test.go similarity index 100% rename from internal/configs/configschema/empty_value_test.go rename to configs/configschema/empty_value_test.go diff --git a/internal/configs/configschema/implied_type.go b/configs/configschema/implied_type.go similarity index 100% rename from internal/configs/configschema/implied_type.go rename to configs/configschema/implied_type.go diff --git a/internal/configs/configschema/implied_type_test.go b/configs/configschema/implied_type_test.go similarity index 100% rename from internal/configs/configschema/implied_type_test.go rename to configs/configschema/implied_type_test.go diff --git a/internal/configs/configschema/internal_validate.go b/configs/configschema/internal_validate.go similarity index 100% rename from internal/configs/configschema/internal_validate.go rename to configs/configschema/internal_validate.go diff --git a/internal/configs/configschema/internal_validate_test.go b/configs/configschema/internal_validate_test.go similarity index 100% rename from internal/configs/configschema/internal_validate_test.go rename to configs/configschema/internal_validate_test.go diff --git a/internal/configs/configschema/marks.go b/configs/configschema/marks.go similarity index 99% rename from internal/configs/configschema/marks.go rename to configs/configschema/marks.go index f16bad711e1c..92fed660ae38 100644 --- a/internal/configs/configschema/marks.go +++ b/configs/configschema/marks.go @@ -3,7 +3,7 @@ package configschema import ( "fmt" - "github.com/hashicorp/terraform/internal/lang/marks" + "github.com/hashicorp/terraform/lang/marks" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/configs/configschema/marks_test.go b/configs/configschema/marks_test.go similarity index 98% rename from internal/configs/configschema/marks_test.go rename to configs/configschema/marks_test.go index 2077e5e805b0..2bd8f9651f84 100644 --- a/internal/configs/configschema/marks_test.go +++ b/configs/configschema/marks_test.go @@ -3,7 +3,7 @@ package configschema import ( "testing" - "github.com/hashicorp/terraform/internal/lang/marks" + "github.com/hashicorp/terraform/lang/marks" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/configs/configschema/nestingmode_string.go b/configs/configschema/nestingmode_string.go similarity index 100% rename from internal/configs/configschema/nestingmode_string.go rename to configs/configschema/nestingmode_string.go diff --git a/internal/configs/configschema/none_required.go b/configs/configschema/none_required.go similarity index 100% rename from internal/configs/configschema/none_required.go rename to configs/configschema/none_required.go diff --git a/internal/configs/configschema/path.go b/configs/configschema/path.go similarity index 100% rename from internal/configs/configschema/path.go rename to configs/configschema/path.go diff --git a/internal/configs/configschema/path_test.go b/configs/configschema/path_test.go similarity index 100% rename from internal/configs/configschema/path_test.go rename to configs/configschema/path_test.go diff --git a/internal/configs/configschema/schema.go b/configs/configschema/schema.go similarity index 100% rename from internal/configs/configschema/schema.go rename to configs/configschema/schema.go diff --git a/internal/configs/configschema/validate_traversal.go b/configs/configschema/validate_traversal.go similarity index 98% rename from internal/configs/configschema/validate_traversal.go rename to configs/configschema/validate_traversal.go index 8320c9de3663..4ef50e31c453 100644 --- a/internal/configs/configschema/validate_traversal.go +++ b/configs/configschema/validate_traversal.go @@ -8,8 +8,8 @@ import ( "github.com/hashicorp/hcl/v2/hclsyntax" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/didyoumean" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/didyoumean" + "github.com/hashicorp/terraform/tfdiags" ) // StaticValidateTraversal checks whether the given traversal (which must be diff --git a/internal/configs/configschema/validate_traversal_test.go b/configs/configschema/validate_traversal_test.go similarity index 100% rename from internal/configs/configschema/validate_traversal_test.go rename to configs/configschema/validate_traversal_test.go diff --git a/internal/configs/depends_on.go b/configs/depends_on.go similarity index 100% rename from internal/configs/depends_on.go rename to configs/depends_on.go diff --git a/internal/configs/doc.go b/configs/doc.go similarity index 100% rename from internal/configs/doc.go rename to configs/doc.go diff --git a/internal/configs/escaping_blocks_test.go b/configs/escaping_blocks_test.go similarity index 100% rename from internal/configs/escaping_blocks_test.go rename to configs/escaping_blocks_test.go diff --git a/internal/configs/experiments.go b/configs/experiments.go similarity index 98% rename from internal/configs/experiments.go rename to configs/experiments.go index 1d1a36b02069..4b6df3b10096 100644 --- a/internal/configs/experiments.go +++ b/configs/experiments.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/experiments" + "github.com/hashicorp/terraform/experiments" "github.com/hashicorp/terraform/version" ) @@ -12,7 +12,7 @@ import ( // the experiment warning by setting this package-level variable to a non-empty // value using a link-time flag: // -// go install -ldflags="-X 'github.com/hashicorp/terraform/internal/configs.disableExperimentWarnings=yes'" +// go install -ldflags="-X 'github.com/hashicorp/terraform/configs.disableExperimentWarnings=yes'" // // This functionality is for development purposes only and is not a feature we // are committing to supporting for end users. diff --git a/internal/configs/experiments_test.go b/configs/experiments_test.go similarity index 98% rename from internal/configs/experiments_test.go rename to configs/experiments_test.go index 7d1b9dc4e391..be60d278ff49 100644 --- a/internal/configs/experiments_test.go +++ b/configs/experiments_test.go @@ -6,7 +6,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/experiments" + "github.com/hashicorp/terraform/experiments" ) func TestExperimentsConfig(t *testing.T) { diff --git a/internal/configs/hcl2shim/flatmap.go b/configs/hcl2shim/flatmap.go similarity index 100% rename from internal/configs/hcl2shim/flatmap.go rename to configs/hcl2shim/flatmap.go diff --git a/internal/configs/hcl2shim/flatmap_test.go b/configs/hcl2shim/flatmap_test.go similarity index 100% rename from internal/configs/hcl2shim/flatmap_test.go rename to configs/hcl2shim/flatmap_test.go diff --git a/internal/configs/hcl2shim/paths.go b/configs/hcl2shim/paths.go similarity index 100% rename from internal/configs/hcl2shim/paths.go rename to configs/hcl2shim/paths.go diff --git a/internal/configs/hcl2shim/paths_test.go b/configs/hcl2shim/paths_test.go similarity index 100% rename from internal/configs/hcl2shim/paths_test.go rename to configs/hcl2shim/paths_test.go diff --git a/internal/configs/hcl2shim/single_attr_body.go b/configs/hcl2shim/single_attr_body.go similarity index 100% rename from internal/configs/hcl2shim/single_attr_body.go rename to configs/hcl2shim/single_attr_body.go diff --git a/internal/configs/hcl2shim/values.go b/configs/hcl2shim/values.go similarity index 99% rename from internal/configs/hcl2shim/values.go rename to configs/hcl2shim/values.go index 7b0e09607f83..44551fe1ea20 100644 --- a/internal/configs/hcl2shim/values.go +++ b/configs/hcl2shim/values.go @@ -6,7 +6,7 @@ import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/configs/configschema" + "github.com/hashicorp/terraform/configs/configschema" ) // UnknownVariableValue is a sentinel value that can be used diff --git a/internal/configs/hcl2shim/values_equiv.go b/configs/hcl2shim/values_equiv.go similarity index 100% rename from internal/configs/hcl2shim/values_equiv.go rename to configs/hcl2shim/values_equiv.go diff --git a/internal/configs/hcl2shim/values_equiv_test.go b/configs/hcl2shim/values_equiv_test.go similarity index 100% rename from internal/configs/hcl2shim/values_equiv_test.go rename to configs/hcl2shim/values_equiv_test.go diff --git a/internal/configs/hcl2shim/values_test.go b/configs/hcl2shim/values_test.go similarity index 99% rename from internal/configs/hcl2shim/values_test.go rename to configs/hcl2shim/values_test.go index 4bc816dd9be5..7c3011da053c 100644 --- a/internal/configs/hcl2shim/values_test.go +++ b/configs/hcl2shim/values_test.go @@ -5,7 +5,7 @@ import ( "reflect" "testing" - "github.com/hashicorp/terraform/internal/configs/configschema" + "github.com/hashicorp/terraform/configs/configschema" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/configs/module.go b/configs/module.go similarity index 99% rename from internal/configs/module.go rename to configs/module.go index c2088b9fde9c..caefb966b606 100644 --- a/internal/configs/module.go +++ b/configs/module.go @@ -5,8 +5,8 @@ import ( "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/experiments" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/experiments" ) // Module is a container for a set of configuration constructs that are diff --git a/internal/configs/module_call.go b/configs/module_call.go similarity index 98% rename from internal/configs/module_call.go rename to configs/module_call.go index 3ec42ec01a17..d261de8639a3 100644 --- a/internal/configs/module_call.go +++ b/configs/module_call.go @@ -6,8 +6,8 @@ import ( "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/gohcl" "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/getmodules" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/getmodules" ) // ModuleCall represents a "module" block in a module or file. diff --git a/internal/configs/module_call_test.go b/configs/module_call_test.go similarity index 99% rename from internal/configs/module_call_test.go rename to configs/module_call_test.go index af2269dca0bb..c7dfa1409e14 100644 --- a/internal/configs/module_call_test.go +++ b/configs/module_call_test.go @@ -6,7 +6,7 @@ import ( "github.com/go-test/deep" "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) func TestLoadModuleCall(t *testing.T) { diff --git a/internal/configs/module_merge.go b/configs/module_merge.go similarity index 99% rename from internal/configs/module_merge.go rename to configs/module_merge.go index 9494343f2e8a..8efc3fb80b7f 100644 --- a/internal/configs/module_merge.go +++ b/configs/module_merge.go @@ -3,7 +3,7 @@ package configs import ( "fmt" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" "github.com/hashicorp/hcl/v2" "github.com/zclconf/go-cty/cty" diff --git a/internal/configs/module_merge_body.go b/configs/module_merge_body.go similarity index 100% rename from internal/configs/module_merge_body.go rename to configs/module_merge_body.go diff --git a/internal/configs/module_merge_test.go b/configs/module_merge_test.go similarity index 99% rename from internal/configs/module_merge_test.go rename to configs/module_merge_test.go index 5d590661c728..4e77fb913108 100644 --- a/internal/configs/module_merge_test.go +++ b/configs/module_merge_test.go @@ -6,7 +6,7 @@ import ( "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/gohcl" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/configs/module_test.go b/configs/module_test.go similarity index 99% rename from internal/configs/module_test.go rename to configs/module_test.go index 5a74dda3e36d..7a6b1e7d2388 100644 --- a/internal/configs/module_test.go +++ b/configs/module_test.go @@ -4,7 +4,7 @@ import ( "strings" "testing" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/configs/moved.go b/configs/moved.go similarity index 97% rename from internal/configs/moved.go rename to configs/moved.go index 5cfbd5dfb01e..f892cbc07b6e 100644 --- a/internal/configs/moved.go +++ b/configs/moved.go @@ -2,7 +2,7 @@ package configs import ( "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) type Moved struct { diff --git a/internal/configs/moved_test.go b/configs/moved_test.go similarity index 98% rename from internal/configs/moved_test.go rename to configs/moved_test.go index 433525d28c17..ec5fe203f8f0 100644 --- a/internal/configs/moved_test.go +++ b/configs/moved_test.go @@ -6,7 +6,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hcltest" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) func TestMovedBlock_decode(t *testing.T) { diff --git a/internal/configs/named_values.go b/configs/named_values.go similarity index 99% rename from internal/configs/named_values.go rename to configs/named_values.go index 3ce759c8713e..abfe0779ff24 100644 --- a/internal/configs/named_values.go +++ b/configs/named_values.go @@ -10,7 +10,7 @@ import ( "github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty/convert" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) // A consistent detail message for all "not a valid identifier" diagnostics. diff --git a/internal/configs/parser.go b/configs/parser.go similarity index 100% rename from internal/configs/parser.go rename to configs/parser.go diff --git a/internal/configs/parser_config.go b/configs/parser_config.go similarity index 100% rename from internal/configs/parser_config.go rename to configs/parser_config.go diff --git a/internal/configs/parser_config_dir.go b/configs/parser_config_dir.go similarity index 100% rename from internal/configs/parser_config_dir.go rename to configs/parser_config_dir.go diff --git a/internal/configs/parser_config_dir_test.go b/configs/parser_config_dir_test.go similarity index 100% rename from internal/configs/parser_config_dir_test.go rename to configs/parser_config_dir_test.go diff --git a/internal/configs/parser_config_test.go b/configs/parser_config_test.go similarity index 100% rename from internal/configs/parser_config_test.go rename to configs/parser_config_test.go diff --git a/internal/configs/parser_test.go b/configs/parser_test.go similarity index 100% rename from internal/configs/parser_test.go rename to configs/parser_test.go diff --git a/internal/configs/parser_values.go b/configs/parser_values.go similarity index 100% rename from internal/configs/parser_values.go rename to configs/parser_values.go diff --git a/internal/configs/parser_values_test.go b/configs/parser_values_test.go similarity index 100% rename from internal/configs/parser_values_test.go rename to configs/parser_values_test.go diff --git a/internal/configs/provider.go b/configs/provider.go similarity index 98% rename from internal/configs/provider.go rename to configs/provider.go index 6ed24f63af39..beb56f424e4a 100644 --- a/internal/configs/provider.go +++ b/configs/provider.go @@ -7,8 +7,8 @@ import ( "github.com/hashicorp/hcl/v2/gohcl" "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/tfdiags" ) // Provider represents a "provider" block in a module or file. A provider diff --git a/internal/configs/provider_meta.go b/configs/provider_meta.go similarity index 100% rename from internal/configs/provider_meta.go rename to configs/provider_meta.go diff --git a/internal/configs/provider_requirements.go b/configs/provider_requirements.go similarity index 99% rename from internal/configs/provider_requirements.go rename to configs/provider_requirements.go index c982c1a37cd8..736e3636f66e 100644 --- a/internal/configs/provider_requirements.go +++ b/configs/provider_requirements.go @@ -5,7 +5,7 @@ import ( version "github.com/hashicorp/go-version" "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/configs/provider_requirements_test.go b/configs/provider_requirements_test.go similarity index 99% rename from internal/configs/provider_requirements_test.go rename to configs/provider_requirements_test.go index 8d00f6190294..d580f964e8f3 100644 --- a/internal/configs/provider_requirements_test.go +++ b/configs/provider_requirements_test.go @@ -8,7 +8,7 @@ import ( version "github.com/hashicorp/go-version" "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hcltest" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/configs/provider_test.go b/configs/provider_test.go similarity index 98% rename from internal/configs/provider_test.go rename to configs/provider_test.go index 65924f085fee..db8089f910d7 100644 --- a/internal/configs/provider_test.go +++ b/configs/provider_test.go @@ -7,7 +7,7 @@ import ( "github.com/go-test/deep" "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) func TestProviderReservedNames(t *testing.T) { diff --git a/internal/configs/provider_validation.go b/configs/provider_validation.go similarity index 99% rename from internal/configs/provider_validation.go rename to configs/provider_validation.go index 0cf7378d3639..1955b6dde3bf 100644 --- a/internal/configs/provider_validation.go +++ b/configs/provider_validation.go @@ -6,7 +6,7 @@ import ( "strings" "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) // validateProviderConfigs walks the full configuration tree from the root diff --git a/internal/configs/provisioner.go b/configs/provisioner.go similarity index 100% rename from internal/configs/provisioner.go rename to configs/provisioner.go diff --git a/internal/configs/provisioneronfailure_string.go b/configs/provisioneronfailure_string.go similarity index 100% rename from internal/configs/provisioneronfailure_string.go rename to configs/provisioneronfailure_string.go diff --git a/internal/configs/provisionerwhen_string.go b/configs/provisionerwhen_string.go similarity index 100% rename from internal/configs/provisionerwhen_string.go rename to configs/provisionerwhen_string.go diff --git a/internal/configs/resource.go b/configs/resource.go similarity index 99% rename from internal/configs/resource.go rename to configs/resource.go index 1f67c6c40f68..561877075972 100644 --- a/internal/configs/resource.go +++ b/configs/resource.go @@ -8,9 +8,9 @@ import ( "github.com/hashicorp/hcl/v2/hclsyntax" hcljson "github.com/hashicorp/hcl/v2/json" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/lang" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/lang" + "github.com/hashicorp/terraform/tfdiags" ) // Resource represents a "resource" or "data" block in a module or file. diff --git a/internal/configs/synth_body.go b/configs/synth_body.go similarity index 100% rename from internal/configs/synth_body.go rename to configs/synth_body.go diff --git a/internal/configs/synth_body_test.go b/configs/synth_body_test.go similarity index 100% rename from internal/configs/synth_body_test.go rename to configs/synth_body_test.go diff --git a/internal/configs/testdata/config-build/child_a/child_a.tf b/configs/testdata/config-build/child_a/child_a.tf similarity index 100% rename from internal/configs/testdata/config-build/child_a/child_a.tf rename to configs/testdata/config-build/child_a/child_a.tf diff --git a/internal/configs/testdata/config-build/child_b/child_b.tf b/configs/testdata/config-build/child_b/child_b.tf similarity index 100% rename from internal/configs/testdata/config-build/child_b/child_b.tf rename to configs/testdata/config-build/child_b/child_b.tf diff --git a/internal/configs/testdata/config-build/child_c/child_c.tf b/configs/testdata/config-build/child_c/child_c.tf similarity index 100% rename from internal/configs/testdata/config-build/child_c/child_c.tf rename to configs/testdata/config-build/child_c/child_c.tf diff --git a/internal/configs/testdata/config-build/root.tf b/configs/testdata/config-build/root.tf similarity index 100% rename from internal/configs/testdata/config-build/root.tf rename to configs/testdata/config-build/root.tf diff --git a/internal/configs/testdata/config-diagnostics/empty-configs/main.tf b/configs/testdata/config-diagnostics/empty-configs/main.tf similarity index 100% rename from internal/configs/testdata/config-diagnostics/empty-configs/main.tf rename to configs/testdata/config-diagnostics/empty-configs/main.tf diff --git a/internal/configs/testdata/config-diagnostics/empty-configs/mod/main.tf b/configs/testdata/config-diagnostics/empty-configs/mod/main.tf similarity index 100% rename from internal/configs/testdata/config-diagnostics/empty-configs/mod/main.tf rename to configs/testdata/config-diagnostics/empty-configs/mod/main.tf diff --git a/internal/configs/testdata/config-diagnostics/empty-configs/warnings b/configs/testdata/config-diagnostics/empty-configs/warnings similarity index 100% rename from internal/configs/testdata/config-diagnostics/empty-configs/warnings rename to configs/testdata/config-diagnostics/empty-configs/warnings diff --git a/internal/configs/testdata/config-diagnostics/incorrect-type/errors b/configs/testdata/config-diagnostics/incorrect-type/errors similarity index 100% rename from internal/configs/testdata/config-diagnostics/incorrect-type/errors rename to configs/testdata/config-diagnostics/incorrect-type/errors diff --git a/internal/configs/testdata/config-diagnostics/incorrect-type/main.tf b/configs/testdata/config-diagnostics/incorrect-type/main.tf similarity index 100% rename from internal/configs/testdata/config-diagnostics/incorrect-type/main.tf rename to configs/testdata/config-diagnostics/incorrect-type/main.tf diff --git a/internal/configs/testdata/config-diagnostics/incorrect-type/mod/main.tf b/configs/testdata/config-diagnostics/incorrect-type/mod/main.tf similarity index 100% rename from internal/configs/testdata/config-diagnostics/incorrect-type/mod/main.tf rename to configs/testdata/config-diagnostics/incorrect-type/mod/main.tf diff --git a/internal/configs/testdata/config-diagnostics/incorrect-type/warnings b/configs/testdata/config-diagnostics/incorrect-type/warnings similarity index 100% rename from internal/configs/testdata/config-diagnostics/incorrect-type/warnings rename to configs/testdata/config-diagnostics/incorrect-type/warnings diff --git a/internal/configs/testdata/config-diagnostics/invalid-provider/errors b/configs/testdata/config-diagnostics/invalid-provider/errors similarity index 100% rename from internal/configs/testdata/config-diagnostics/invalid-provider/errors rename to configs/testdata/config-diagnostics/invalid-provider/errors diff --git a/internal/configs/testdata/config-diagnostics/invalid-provider/main.tf b/configs/testdata/config-diagnostics/invalid-provider/main.tf similarity index 100% rename from internal/configs/testdata/config-diagnostics/invalid-provider/main.tf rename to configs/testdata/config-diagnostics/invalid-provider/main.tf diff --git a/internal/configs/testdata/config-diagnostics/invalid-provider/mod/main.tf b/configs/testdata/config-diagnostics/invalid-provider/mod/main.tf similarity index 100% rename from internal/configs/testdata/config-diagnostics/invalid-provider/mod/main.tf rename to configs/testdata/config-diagnostics/invalid-provider/mod/main.tf diff --git a/internal/configs/testdata/config-diagnostics/nested-provider/child/child2/main.tf b/configs/testdata/config-diagnostics/nested-provider/child/child2/main.tf similarity index 100% rename from internal/configs/testdata/config-diagnostics/nested-provider/child/child2/main.tf rename to configs/testdata/config-diagnostics/nested-provider/child/child2/main.tf diff --git a/internal/configs/testdata/config-diagnostics/nested-provider/child/main.tf b/configs/testdata/config-diagnostics/nested-provider/child/main.tf similarity index 100% rename from internal/configs/testdata/config-diagnostics/nested-provider/child/main.tf rename to configs/testdata/config-diagnostics/nested-provider/child/main.tf diff --git a/internal/configs/testdata/config-diagnostics/nested-provider/errors b/configs/testdata/config-diagnostics/nested-provider/errors similarity index 100% rename from internal/configs/testdata/config-diagnostics/nested-provider/errors rename to configs/testdata/config-diagnostics/nested-provider/errors diff --git a/internal/configs/testdata/config-diagnostics/nested-provider/root.tf b/configs/testdata/config-diagnostics/nested-provider/root.tf similarity index 100% rename from internal/configs/testdata/config-diagnostics/nested-provider/root.tf rename to configs/testdata/config-diagnostics/nested-provider/root.tf diff --git a/internal/configs/testdata/config-diagnostics/override-provider/errors b/configs/testdata/config-diagnostics/override-provider/errors similarity index 100% rename from internal/configs/testdata/config-diagnostics/override-provider/errors rename to configs/testdata/config-diagnostics/override-provider/errors diff --git a/internal/configs/testdata/config-diagnostics/override-provider/main.tf b/configs/testdata/config-diagnostics/override-provider/main.tf similarity index 100% rename from internal/configs/testdata/config-diagnostics/override-provider/main.tf rename to configs/testdata/config-diagnostics/override-provider/main.tf diff --git a/internal/configs/testdata/config-diagnostics/override-provider/mod/main.tf b/configs/testdata/config-diagnostics/override-provider/mod/main.tf similarity index 100% rename from internal/configs/testdata/config-diagnostics/override-provider/mod/main.tf rename to configs/testdata/config-diagnostics/override-provider/mod/main.tf diff --git a/internal/configs/testdata/config-diagnostics/pass-inherited-provider/main.tf b/configs/testdata/config-diagnostics/pass-inherited-provider/main.tf similarity index 100% rename from internal/configs/testdata/config-diagnostics/pass-inherited-provider/main.tf rename to configs/testdata/config-diagnostics/pass-inherited-provider/main.tf diff --git a/internal/configs/testdata/config-diagnostics/pass-inherited-provider/mod/main.tf b/configs/testdata/config-diagnostics/pass-inherited-provider/mod/main.tf similarity index 100% rename from internal/configs/testdata/config-diagnostics/pass-inherited-provider/mod/main.tf rename to configs/testdata/config-diagnostics/pass-inherited-provider/mod/main.tf diff --git a/internal/configs/testdata/config-diagnostics/pass-inherited-provider/mod2/main.tf b/configs/testdata/config-diagnostics/pass-inherited-provider/mod2/main.tf similarity index 100% rename from internal/configs/testdata/config-diagnostics/pass-inherited-provider/mod2/main.tf rename to configs/testdata/config-diagnostics/pass-inherited-provider/mod2/main.tf diff --git a/internal/configs/testdata/config-diagnostics/pass-inherited-provider/warnings b/configs/testdata/config-diagnostics/pass-inherited-provider/warnings similarity index 100% rename from internal/configs/testdata/config-diagnostics/pass-inherited-provider/warnings rename to configs/testdata/config-diagnostics/pass-inherited-provider/warnings diff --git a/internal/configs/testdata/config-diagnostics/required-alias/errors b/configs/testdata/config-diagnostics/required-alias/errors similarity index 100% rename from internal/configs/testdata/config-diagnostics/required-alias/errors rename to configs/testdata/config-diagnostics/required-alias/errors diff --git a/internal/configs/testdata/config-diagnostics/required-alias/main.tf b/configs/testdata/config-diagnostics/required-alias/main.tf similarity index 100% rename from internal/configs/testdata/config-diagnostics/required-alias/main.tf rename to configs/testdata/config-diagnostics/required-alias/main.tf diff --git a/internal/configs/testdata/config-diagnostics/required-alias/mod/main.tf b/configs/testdata/config-diagnostics/required-alias/mod/main.tf similarity index 100% rename from internal/configs/testdata/config-diagnostics/required-alias/mod/main.tf rename to configs/testdata/config-diagnostics/required-alias/mod/main.tf diff --git a/internal/configs/testdata/config-diagnostics/unexpected-provider/main.tf b/configs/testdata/config-diagnostics/unexpected-provider/main.tf similarity index 100% rename from internal/configs/testdata/config-diagnostics/unexpected-provider/main.tf rename to configs/testdata/config-diagnostics/unexpected-provider/main.tf diff --git a/internal/configs/testdata/config-diagnostics/unexpected-provider/mod/main.tf b/configs/testdata/config-diagnostics/unexpected-provider/mod/main.tf similarity index 100% rename from internal/configs/testdata/config-diagnostics/unexpected-provider/mod/main.tf rename to configs/testdata/config-diagnostics/unexpected-provider/mod/main.tf diff --git a/internal/configs/testdata/config-diagnostics/unexpected-provider/warnings b/configs/testdata/config-diagnostics/unexpected-provider/warnings similarity index 100% rename from internal/configs/testdata/config-diagnostics/unexpected-provider/warnings rename to configs/testdata/config-diagnostics/unexpected-provider/warnings diff --git a/internal/configs/testdata/config-diagnostics/unknown-root-provider/main.tf b/configs/testdata/config-diagnostics/unknown-root-provider/main.tf similarity index 100% rename from internal/configs/testdata/config-diagnostics/unknown-root-provider/main.tf rename to configs/testdata/config-diagnostics/unknown-root-provider/main.tf diff --git a/internal/configs/testdata/config-diagnostics/unknown-root-provider/mod/main.tf b/configs/testdata/config-diagnostics/unknown-root-provider/mod/main.tf similarity index 100% rename from internal/configs/testdata/config-diagnostics/unknown-root-provider/mod/main.tf rename to configs/testdata/config-diagnostics/unknown-root-provider/mod/main.tf diff --git a/internal/configs/testdata/config-diagnostics/unknown-root-provider/warnings b/configs/testdata/config-diagnostics/unknown-root-provider/warnings similarity index 100% rename from internal/configs/testdata/config-diagnostics/unknown-root-provider/warnings rename to configs/testdata/config-diagnostics/unknown-root-provider/warnings diff --git a/internal/configs/testdata/config-diagnostics/with-depends-on/main.tf b/configs/testdata/config-diagnostics/with-depends-on/main.tf similarity index 100% rename from internal/configs/testdata/config-diagnostics/with-depends-on/main.tf rename to configs/testdata/config-diagnostics/with-depends-on/main.tf diff --git a/internal/configs/testdata/config-diagnostics/with-depends-on/mod1/main.tf b/configs/testdata/config-diagnostics/with-depends-on/mod1/main.tf similarity index 100% rename from internal/configs/testdata/config-diagnostics/with-depends-on/mod1/main.tf rename to configs/testdata/config-diagnostics/with-depends-on/mod1/main.tf diff --git a/internal/configs/testdata/config-diagnostics/with-depends-on/mod1/mod2/main.tf b/configs/testdata/config-diagnostics/with-depends-on/mod1/mod2/main.tf similarity index 100% rename from internal/configs/testdata/config-diagnostics/with-depends-on/mod1/mod2/main.tf rename to configs/testdata/config-diagnostics/with-depends-on/mod1/mod2/main.tf diff --git a/internal/configs/testdata/config-diagnostics/with-depends-on/mod1/mod2/mod3/main.tf b/configs/testdata/config-diagnostics/with-depends-on/mod1/mod2/mod3/main.tf similarity index 100% rename from internal/configs/testdata/config-diagnostics/with-depends-on/mod1/mod2/mod3/main.tf rename to configs/testdata/config-diagnostics/with-depends-on/mod1/mod2/mod3/main.tf diff --git a/internal/configs/testdata/dir-empty/.gitkeep b/configs/testdata/dir-empty/.gitkeep similarity index 100% rename from internal/configs/testdata/dir-empty/.gitkeep rename to configs/testdata/dir-empty/.gitkeep diff --git a/internal/configs/testdata/duplicate-local-name/main.tf b/configs/testdata/duplicate-local-name/main.tf similarity index 100% rename from internal/configs/testdata/duplicate-local-name/main.tf rename to configs/testdata/duplicate-local-name/main.tf diff --git a/internal/configs/testdata/error-files/destroy-provisioners.tf b/configs/testdata/error-files/destroy-provisioners.tf similarity index 100% rename from internal/configs/testdata/error-files/destroy-provisioners.tf rename to configs/testdata/error-files/destroy-provisioners.tf diff --git a/internal/configs/testdata/error-files/ignore_changes.tf b/configs/testdata/error-files/ignore_changes.tf similarity index 100% rename from internal/configs/testdata/error-files/ignore_changes.tf rename to configs/testdata/error-files/ignore_changes.tf diff --git a/internal/configs/testdata/error-files/invalid_language_edition.tf b/configs/testdata/error-files/invalid_language_edition.tf similarity index 100% rename from internal/configs/testdata/error-files/invalid_language_edition.tf rename to configs/testdata/error-files/invalid_language_edition.tf diff --git a/internal/configs/testdata/error-files/module-invalid-registry-source-with-module.tf b/configs/testdata/error-files/module-invalid-registry-source-with-module.tf similarity index 100% rename from internal/configs/testdata/error-files/module-invalid-registry-source-with-module.tf rename to configs/testdata/error-files/module-invalid-registry-source-with-module.tf diff --git a/internal/configs/testdata/error-files/module-local-source-with-version.tf b/configs/testdata/error-files/module-local-source-with-version.tf similarity index 100% rename from internal/configs/testdata/error-files/module-local-source-with-version.tf rename to configs/testdata/error-files/module-local-source-with-version.tf diff --git a/internal/configs/testdata/error-files/precondition-postcondition-constant.tf b/configs/testdata/error-files/precondition-postcondition-constant.tf similarity index 100% rename from internal/configs/testdata/error-files/precondition-postcondition-constant.tf rename to configs/testdata/error-files/precondition-postcondition-constant.tf diff --git a/internal/configs/testdata/error-files/precondition-postcondition-selfref.tf b/configs/testdata/error-files/precondition-postcondition-selfref.tf similarity index 100% rename from internal/configs/testdata/error-files/precondition-postcondition-selfref.tf rename to configs/testdata/error-files/precondition-postcondition-selfref.tf diff --git a/internal/configs/testdata/error-files/provider-source-prefix.tf b/configs/testdata/error-files/provider-source-prefix.tf similarity index 100% rename from internal/configs/testdata/error-files/provider-source-prefix.tf rename to configs/testdata/error-files/provider-source-prefix.tf diff --git a/internal/configs/testdata/error-files/required-providers-toplevel.tf b/configs/testdata/error-files/required-providers-toplevel.tf similarity index 100% rename from internal/configs/testdata/error-files/required-providers-toplevel.tf rename to configs/testdata/error-files/required-providers-toplevel.tf diff --git a/internal/configs/testdata/error-files/unsupported_language_edition.tf b/configs/testdata/error-files/unsupported_language_edition.tf similarity index 100% rename from internal/configs/testdata/error-files/unsupported_language_edition.tf rename to configs/testdata/error-files/unsupported_language_edition.tf diff --git a/internal/configs/testdata/error-files/variable_type_quoted.tf b/configs/testdata/error-files/variable_type_quoted.tf similarity index 100% rename from internal/configs/testdata/error-files/variable_type_quoted.tf rename to configs/testdata/error-files/variable_type_quoted.tf diff --git a/internal/configs/testdata/error-files/vendor_provisioners.tf b/configs/testdata/error-files/vendor_provisioners.tf similarity index 100% rename from internal/configs/testdata/error-files/vendor_provisioners.tf rename to configs/testdata/error-files/vendor_provisioners.tf diff --git a/internal/configs/testdata/escaping-blocks/data/data-escaping-block.tf b/configs/testdata/escaping-blocks/data/data-escaping-block.tf similarity index 100% rename from internal/configs/testdata/escaping-blocks/data/data-escaping-block.tf rename to configs/testdata/escaping-blocks/data/data-escaping-block.tf diff --git a/internal/configs/testdata/escaping-blocks/module/child/nothing.tf b/configs/testdata/escaping-blocks/module/child/nothing.tf similarity index 100% rename from internal/configs/testdata/escaping-blocks/module/child/nothing.tf rename to configs/testdata/escaping-blocks/module/child/nothing.tf diff --git a/internal/configs/testdata/escaping-blocks/module/module-escaping-block.tf b/configs/testdata/escaping-blocks/module/module-escaping-block.tf similarity index 100% rename from internal/configs/testdata/escaping-blocks/module/module-escaping-block.tf rename to configs/testdata/escaping-blocks/module/module-escaping-block.tf diff --git a/internal/configs/testdata/escaping-blocks/provider/provider-escaping-block.tf b/configs/testdata/escaping-blocks/provider/provider-escaping-block.tf similarity index 100% rename from internal/configs/testdata/escaping-blocks/provider/provider-escaping-block.tf rename to configs/testdata/escaping-blocks/provider/provider-escaping-block.tf diff --git a/internal/configs/testdata/escaping-blocks/resource/resource-escaping-block.tf b/configs/testdata/escaping-blocks/resource/resource-escaping-block.tf similarity index 100% rename from internal/configs/testdata/escaping-blocks/resource/resource-escaping-block.tf rename to configs/testdata/escaping-blocks/resource/resource-escaping-block.tf diff --git a/internal/configs/testdata/experiments/concluded/concluded_experiment.tf b/configs/testdata/experiments/concluded/concluded_experiment.tf similarity index 100% rename from internal/configs/testdata/experiments/concluded/concluded_experiment.tf rename to configs/testdata/experiments/concluded/concluded_experiment.tf diff --git a/internal/configs/testdata/experiments/current/current_experiment.tf b/configs/testdata/experiments/current/current_experiment.tf similarity index 100% rename from internal/configs/testdata/experiments/current/current_experiment.tf rename to configs/testdata/experiments/current/current_experiment.tf diff --git a/internal/configs/testdata/experiments/invalid/invalid_experiments.tf b/configs/testdata/experiments/invalid/invalid_experiments.tf similarity index 100% rename from internal/configs/testdata/experiments/invalid/invalid_experiments.tf rename to configs/testdata/experiments/invalid/invalid_experiments.tf diff --git a/internal/configs/testdata/experiments/unknown/unknown_experiment.tf b/configs/testdata/experiments/unknown/unknown_experiment.tf similarity index 100% rename from internal/configs/testdata/experiments/unknown/unknown_experiment.tf rename to configs/testdata/experiments/unknown/unknown_experiment.tf diff --git a/internal/configs/testdata/invalid-files/data-count-and-for_each.tf b/configs/testdata/invalid-files/data-count-and-for_each.tf similarity index 100% rename from internal/configs/testdata/invalid-files/data-count-and-for_each.tf rename to configs/testdata/invalid-files/data-count-and-for_each.tf diff --git a/internal/configs/testdata/invalid-files/data-invalid-provider-reference.tf b/configs/testdata/invalid-files/data-invalid-provider-reference.tf similarity index 100% rename from internal/configs/testdata/invalid-files/data-invalid-provider-reference.tf rename to configs/testdata/invalid-files/data-invalid-provider-reference.tf diff --git a/internal/configs/testdata/invalid-files/data-reserved-locals.tf b/configs/testdata/invalid-files/data-reserved-locals.tf similarity index 100% rename from internal/configs/testdata/invalid-files/data-reserved-locals.tf rename to configs/testdata/invalid-files/data-reserved-locals.tf diff --git a/internal/configs/testdata/invalid-files/data-resource-lifecycle.tf b/configs/testdata/invalid-files/data-resource-lifecycle.tf similarity index 100% rename from internal/configs/testdata/invalid-files/data-resource-lifecycle.tf rename to configs/testdata/invalid-files/data-resource-lifecycle.tf diff --git a/internal/configs/testdata/invalid-files/everything-is-a-plan.tf b/configs/testdata/invalid-files/everything-is-a-plan.tf similarity index 100% rename from internal/configs/testdata/invalid-files/everything-is-a-plan.tf rename to configs/testdata/invalid-files/everything-is-a-plan.tf diff --git a/internal/configs/testdata/invalid-files/interp-in-data-label.tf b/configs/testdata/invalid-files/interp-in-data-label.tf similarity index 100% rename from internal/configs/testdata/invalid-files/interp-in-data-label.tf rename to configs/testdata/invalid-files/interp-in-data-label.tf diff --git a/internal/configs/testdata/invalid-files/interp-in-rsrc-label.tf b/configs/testdata/invalid-files/interp-in-rsrc-label.tf similarity index 100% rename from internal/configs/testdata/invalid-files/interp-in-rsrc-label.tf rename to configs/testdata/invalid-files/interp-in-rsrc-label.tf diff --git a/internal/configs/testdata/invalid-files/json-as-native-syntax.tf b/configs/testdata/invalid-files/json-as-native-syntax.tf similarity index 100% rename from internal/configs/testdata/invalid-files/json-as-native-syntax.tf rename to configs/testdata/invalid-files/json-as-native-syntax.tf diff --git a/internal/configs/testdata/invalid-files/module-calls.tf b/configs/testdata/invalid-files/module-calls.tf similarity index 100% rename from internal/configs/testdata/invalid-files/module-calls.tf rename to configs/testdata/invalid-files/module-calls.tf diff --git a/internal/configs/testdata/invalid-files/native-syntax-as-json.tf.json b/configs/testdata/invalid-files/native-syntax-as-json.tf.json similarity index 100% rename from internal/configs/testdata/invalid-files/native-syntax-as-json.tf.json rename to configs/testdata/invalid-files/native-syntax-as-json.tf.json diff --git a/internal/configs/testdata/invalid-files/precondition-postcondition-badref.tf b/configs/testdata/invalid-files/precondition-postcondition-badref.tf similarity index 100% rename from internal/configs/testdata/invalid-files/precondition-postcondition-badref.tf rename to configs/testdata/invalid-files/precondition-postcondition-badref.tf diff --git a/internal/configs/testdata/invalid-files/precondition-postcondition-missing-condition.tf b/configs/testdata/invalid-files/precondition-postcondition-missing-condition.tf similarity index 100% rename from internal/configs/testdata/invalid-files/precondition-postcondition-missing-condition.tf rename to configs/testdata/invalid-files/precondition-postcondition-missing-condition.tf diff --git a/internal/configs/testdata/invalid-files/provider-localname-normalization.tf b/configs/testdata/invalid-files/provider-localname-normalization.tf similarity index 100% rename from internal/configs/testdata/invalid-files/provider-localname-normalization.tf rename to configs/testdata/invalid-files/provider-localname-normalization.tf diff --git a/internal/configs/testdata/invalid-files/provider-reserved.tf b/configs/testdata/invalid-files/provider-reserved.tf similarity index 100% rename from internal/configs/testdata/invalid-files/provider-reserved.tf rename to configs/testdata/invalid-files/provider-reserved.tf diff --git a/internal/configs/testdata/invalid-files/provider-syntax.tf b/configs/testdata/invalid-files/provider-syntax.tf similarity index 100% rename from internal/configs/testdata/invalid-files/provider-syntax.tf rename to configs/testdata/invalid-files/provider-syntax.tf diff --git a/internal/configs/testdata/invalid-files/resource-count-and-for_each.tf b/configs/testdata/invalid-files/resource-count-and-for_each.tf similarity index 100% rename from internal/configs/testdata/invalid-files/resource-count-and-for_each.tf rename to configs/testdata/invalid-files/resource-count-and-for_each.tf diff --git a/internal/configs/testdata/invalid-files/resource-invalid-provider-reference.tf b/configs/testdata/invalid-files/resource-invalid-provider-reference.tf similarity index 100% rename from internal/configs/testdata/invalid-files/resource-invalid-provider-reference.tf rename to configs/testdata/invalid-files/resource-invalid-provider-reference.tf diff --git a/internal/configs/testdata/invalid-files/resource-lifecycle-badbool.tf b/configs/testdata/invalid-files/resource-lifecycle-badbool.tf similarity index 100% rename from internal/configs/testdata/invalid-files/resource-lifecycle-badbool.tf rename to configs/testdata/invalid-files/resource-lifecycle-badbool.tf diff --git a/internal/configs/testdata/invalid-files/resource-name-invalid.tf b/configs/testdata/invalid-files/resource-name-invalid.tf similarity index 100% rename from internal/configs/testdata/invalid-files/resource-name-invalid.tf rename to configs/testdata/invalid-files/resource-name-invalid.tf diff --git a/internal/configs/testdata/invalid-files/resource-reserved-locals.tf b/configs/testdata/invalid-files/resource-reserved-locals.tf similarity index 100% rename from internal/configs/testdata/invalid-files/resource-reserved-locals.tf rename to configs/testdata/invalid-files/resource-reserved-locals.tf diff --git a/internal/configs/testdata/invalid-files/resources-ignorechanges-all-legacymix.tf b/configs/testdata/invalid-files/resources-ignorechanges-all-legacymix.tf similarity index 100% rename from internal/configs/testdata/invalid-files/resources-ignorechanges-all-legacymix.tf rename to configs/testdata/invalid-files/resources-ignorechanges-all-legacymix.tf diff --git a/internal/configs/testdata/invalid-files/triggered-invalid-each.tf b/configs/testdata/invalid-files/triggered-invalid-each.tf similarity index 100% rename from internal/configs/testdata/invalid-files/triggered-invalid-each.tf rename to configs/testdata/invalid-files/triggered-invalid-each.tf diff --git a/internal/configs/testdata/invalid-files/triggered-invalid-expression.tf b/configs/testdata/invalid-files/triggered-invalid-expression.tf similarity index 100% rename from internal/configs/testdata/invalid-files/triggered-invalid-expression.tf rename to configs/testdata/invalid-files/triggered-invalid-expression.tf diff --git a/internal/configs/testdata/invalid-files/unexpected-attr.tf b/configs/testdata/invalid-files/unexpected-attr.tf similarity index 100% rename from internal/configs/testdata/invalid-files/unexpected-attr.tf rename to configs/testdata/invalid-files/unexpected-attr.tf diff --git a/internal/configs/testdata/invalid-files/unexpected-block.tf b/configs/testdata/invalid-files/unexpected-block.tf similarity index 100% rename from internal/configs/testdata/invalid-files/unexpected-block.tf rename to configs/testdata/invalid-files/unexpected-block.tf diff --git a/internal/configs/testdata/invalid-files/variable-bad-default.tf b/configs/testdata/invalid-files/variable-bad-default.tf similarity index 100% rename from internal/configs/testdata/invalid-files/variable-bad-default.tf rename to configs/testdata/invalid-files/variable-bad-default.tf diff --git a/internal/configs/testdata/invalid-files/variable-bad-sensitive.tf b/configs/testdata/invalid-files/variable-bad-sensitive.tf similarity index 100% rename from internal/configs/testdata/invalid-files/variable-bad-sensitive.tf rename to configs/testdata/invalid-files/variable-bad-sensitive.tf diff --git a/internal/configs/testdata/invalid-files/variable-type-unknown.tf b/configs/testdata/invalid-files/variable-type-unknown.tf similarity index 100% rename from internal/configs/testdata/invalid-files/variable-type-unknown.tf rename to configs/testdata/invalid-files/variable-type-unknown.tf diff --git a/internal/configs/testdata/invalid-files/variable-validation-condition-badref.tf b/configs/testdata/invalid-files/variable-validation-condition-badref.tf similarity index 100% rename from internal/configs/testdata/invalid-files/variable-validation-condition-badref.tf rename to configs/testdata/invalid-files/variable-validation-condition-badref.tf diff --git a/internal/configs/testdata/invalid-files/variable-validation-condition-noref.tf b/configs/testdata/invalid-files/variable-validation-condition-noref.tf similarity index 100% rename from internal/configs/testdata/invalid-files/variable-validation-condition-noref.tf rename to configs/testdata/invalid-files/variable-validation-condition-noref.tf diff --git a/internal/configs/testdata/invalid-files/version-variable.tf b/configs/testdata/invalid-files/version-variable.tf similarity index 100% rename from internal/configs/testdata/invalid-files/version-variable.tf rename to configs/testdata/invalid-files/version-variable.tf diff --git a/internal/configs/testdata/invalid-files/zerolen.tf.json b/configs/testdata/invalid-files/zerolen.tf.json similarity index 100% rename from internal/configs/testdata/invalid-files/zerolen.tf.json rename to configs/testdata/invalid-files/zerolen.tf.json diff --git a/internal/configs/testdata/invalid-modules/multiple-required-providers/a.tf b/configs/testdata/invalid-modules/multiple-required-providers/a.tf similarity index 100% rename from internal/configs/testdata/invalid-modules/multiple-required-providers/a.tf rename to configs/testdata/invalid-modules/multiple-required-providers/a.tf diff --git a/internal/configs/testdata/invalid-modules/multiple-required-providers/b.tf b/configs/testdata/invalid-modules/multiple-required-providers/b.tf similarity index 100% rename from internal/configs/testdata/invalid-modules/multiple-required-providers/b.tf rename to configs/testdata/invalid-modules/multiple-required-providers/b.tf diff --git a/internal/configs/testdata/invalid-modules/nullable-with-default-null/main.tf b/configs/testdata/invalid-modules/nullable-with-default-null/main.tf similarity index 100% rename from internal/configs/testdata/invalid-modules/nullable-with-default-null/main.tf rename to configs/testdata/invalid-modules/nullable-with-default-null/main.tf diff --git a/internal/configs/testdata/invalid-modules/override-cloud-duplicates/main.tf b/configs/testdata/invalid-modules/override-cloud-duplicates/main.tf similarity index 100% rename from internal/configs/testdata/invalid-modules/override-cloud-duplicates/main.tf rename to configs/testdata/invalid-modules/override-cloud-duplicates/main.tf diff --git a/internal/configs/testdata/invalid-modules/override-cloud-duplicates/override.tf b/configs/testdata/invalid-modules/override-cloud-duplicates/override.tf similarity index 100% rename from internal/configs/testdata/invalid-modules/override-cloud-duplicates/override.tf rename to configs/testdata/invalid-modules/override-cloud-duplicates/override.tf diff --git a/internal/configs/testdata/invalid-modules/override-nonexist-variable/override.tf b/configs/testdata/invalid-modules/override-nonexist-variable/override.tf similarity index 100% rename from internal/configs/testdata/invalid-modules/override-nonexist-variable/override.tf rename to configs/testdata/invalid-modules/override-nonexist-variable/override.tf diff --git a/internal/configs/testdata/invalid-modules/override-variable-causes-bad-default/base.tf b/configs/testdata/invalid-modules/override-variable-causes-bad-default/base.tf similarity index 100% rename from internal/configs/testdata/invalid-modules/override-variable-causes-bad-default/base.tf rename to configs/testdata/invalid-modules/override-variable-causes-bad-default/base.tf diff --git a/internal/configs/testdata/invalid-modules/override-variable-causes-bad-default/override.tf b/configs/testdata/invalid-modules/override-variable-causes-bad-default/override.tf similarity index 100% rename from internal/configs/testdata/invalid-modules/override-variable-causes-bad-default/override.tf rename to configs/testdata/invalid-modules/override-variable-causes-bad-default/override.tf diff --git a/internal/configs/testdata/invalid-modules/provider-meta/invalid-interpolation.tf b/configs/testdata/invalid-modules/provider-meta/invalid-interpolation.tf similarity index 100% rename from internal/configs/testdata/invalid-modules/provider-meta/invalid-interpolation.tf rename to configs/testdata/invalid-modules/provider-meta/invalid-interpolation.tf diff --git a/internal/configs/testdata/nested-backend-warning/child/child.tf b/configs/testdata/nested-backend-warning/child/child.tf similarity index 100% rename from internal/configs/testdata/nested-backend-warning/child/child.tf rename to configs/testdata/nested-backend-warning/child/child.tf diff --git a/internal/configs/testdata/nested-backend-warning/root.tf b/configs/testdata/nested-backend-warning/root.tf similarity index 100% rename from internal/configs/testdata/nested-backend-warning/root.tf rename to configs/testdata/nested-backend-warning/root.tf diff --git a/internal/configs/testdata/nested-cloud-warning/child/child.tf b/configs/testdata/nested-cloud-warning/child/child.tf similarity index 100% rename from internal/configs/testdata/nested-cloud-warning/child/child.tf rename to configs/testdata/nested-cloud-warning/child/child.tf diff --git a/internal/configs/testdata/nested-cloud-warning/root.tf b/configs/testdata/nested-cloud-warning/root.tf similarity index 100% rename from internal/configs/testdata/nested-cloud-warning/root.tf rename to configs/testdata/nested-cloud-warning/root.tf diff --git a/internal/configs/testdata/nested-errors/child_a/child_a.tf b/configs/testdata/nested-errors/child_a/child_a.tf similarity index 100% rename from internal/configs/testdata/nested-errors/child_a/child_a.tf rename to configs/testdata/nested-errors/child_a/child_a.tf diff --git a/internal/configs/testdata/nested-errors/child_c/child_c.tf b/configs/testdata/nested-errors/child_c/child_c.tf similarity index 100% rename from internal/configs/testdata/nested-errors/child_c/child_c.tf rename to configs/testdata/nested-errors/child_c/child_c.tf diff --git a/internal/configs/testdata/nested-errors/root.tf b/configs/testdata/nested-errors/root.tf similarity index 100% rename from internal/configs/testdata/nested-errors/root.tf rename to configs/testdata/nested-errors/root.tf diff --git a/internal/configs/testdata/provider-reqs/child/grandchild/provider-reqs-grandchild.tf b/configs/testdata/provider-reqs/child/grandchild/provider-reqs-grandchild.tf similarity index 100% rename from internal/configs/testdata/provider-reqs/child/grandchild/provider-reqs-grandchild.tf rename to configs/testdata/provider-reqs/child/grandchild/provider-reqs-grandchild.tf diff --git a/internal/configs/testdata/provider-reqs/child/provider-reqs-child.tf b/configs/testdata/provider-reqs/child/provider-reqs-child.tf similarity index 100% rename from internal/configs/testdata/provider-reqs/child/provider-reqs-child.tf rename to configs/testdata/provider-reqs/child/provider-reqs-child.tf diff --git a/internal/configs/testdata/provider-reqs/provider-reqs-root.tf b/configs/testdata/provider-reqs/provider-reqs-root.tf similarity index 100% rename from internal/configs/testdata/provider-reqs/provider-reqs-root.tf rename to configs/testdata/provider-reqs/provider-reqs-root.tf diff --git a/internal/configs/testdata/providers-explicit-fqn/root.tf b/configs/testdata/providers-explicit-fqn/root.tf similarity index 100% rename from internal/configs/testdata/providers-explicit-fqn/root.tf rename to configs/testdata/providers-explicit-fqn/root.tf diff --git a/internal/configs/testdata/valid-files/backend.tf b/configs/testdata/valid-files/backend.tf similarity index 100% rename from internal/configs/testdata/valid-files/backend.tf rename to configs/testdata/valid-files/backend.tf diff --git a/internal/configs/testdata/valid-files/cloud.tf b/configs/testdata/valid-files/cloud.tf similarity index 100% rename from internal/configs/testdata/valid-files/cloud.tf rename to configs/testdata/valid-files/cloud.tf diff --git a/internal/configs/testdata/valid-files/data-sources.tf b/configs/testdata/valid-files/data-sources.tf similarity index 100% rename from internal/configs/testdata/valid-files/data-sources.tf rename to configs/testdata/valid-files/data-sources.tf diff --git a/internal/configs/testdata/valid-files/empty.tf b/configs/testdata/valid-files/empty.tf similarity index 100% rename from internal/configs/testdata/valid-files/empty.tf rename to configs/testdata/valid-files/empty.tf diff --git a/internal/configs/testdata/valid-files/empty.tf.json b/configs/testdata/valid-files/empty.tf.json similarity index 100% rename from internal/configs/testdata/valid-files/empty.tf.json rename to configs/testdata/valid-files/empty.tf.json diff --git a/internal/configs/testdata/valid-files/locals.tf b/configs/testdata/valid-files/locals.tf similarity index 100% rename from internal/configs/testdata/valid-files/locals.tf rename to configs/testdata/valid-files/locals.tf diff --git a/internal/configs/testdata/valid-files/locals.tf.json b/configs/testdata/valid-files/locals.tf.json similarity index 100% rename from internal/configs/testdata/valid-files/locals.tf.json rename to configs/testdata/valid-files/locals.tf.json diff --git a/internal/configs/testdata/valid-files/object-optional-attrs.tf b/configs/testdata/valid-files/object-optional-attrs.tf similarity index 100% rename from internal/configs/testdata/valid-files/object-optional-attrs.tf rename to configs/testdata/valid-files/object-optional-attrs.tf diff --git a/internal/configs/testdata/valid-files/outputs.tf b/configs/testdata/valid-files/outputs.tf similarity index 100% rename from internal/configs/testdata/valid-files/outputs.tf rename to configs/testdata/valid-files/outputs.tf diff --git a/internal/configs/testdata/valid-files/preconditions-postconditions.tf b/configs/testdata/valid-files/preconditions-postconditions.tf similarity index 100% rename from internal/configs/testdata/valid-files/preconditions-postconditions.tf rename to configs/testdata/valid-files/preconditions-postconditions.tf diff --git a/internal/configs/testdata/valid-files/provider-configs.tf b/configs/testdata/valid-files/provider-configs.tf similarity index 100% rename from internal/configs/testdata/valid-files/provider-configs.tf rename to configs/testdata/valid-files/provider-configs.tf diff --git a/internal/configs/testdata/valid-files/providers-explicit-implied.tf b/configs/testdata/valid-files/providers-explicit-implied.tf similarity index 100% rename from internal/configs/testdata/valid-files/providers-explicit-implied.tf rename to configs/testdata/valid-files/providers-explicit-implied.tf diff --git a/internal/configs/testdata/valid-files/references.tf.json b/configs/testdata/valid-files/references.tf.json similarity index 100% rename from internal/configs/testdata/valid-files/references.tf.json rename to configs/testdata/valid-files/references.tf.json diff --git a/internal/configs/testdata/valid-files/required-providers.tf b/configs/testdata/valid-files/required-providers.tf similarity index 100% rename from internal/configs/testdata/valid-files/required-providers.tf rename to configs/testdata/valid-files/required-providers.tf diff --git a/internal/configs/testdata/valid-files/required-version.tf b/configs/testdata/valid-files/required-version.tf similarity index 100% rename from internal/configs/testdata/valid-files/required-version.tf rename to configs/testdata/valid-files/required-version.tf diff --git a/internal/configs/testdata/valid-files/resources-ignorechanges-all.tf b/configs/testdata/valid-files/resources-ignorechanges-all.tf similarity index 100% rename from internal/configs/testdata/valid-files/resources-ignorechanges-all.tf rename to configs/testdata/valid-files/resources-ignorechanges-all.tf diff --git a/internal/configs/testdata/valid-files/resources-ignorechanges-all.tf.json b/configs/testdata/valid-files/resources-ignorechanges-all.tf.json similarity index 100% rename from internal/configs/testdata/valid-files/resources-ignorechanges-all.tf.json rename to configs/testdata/valid-files/resources-ignorechanges-all.tf.json diff --git a/internal/configs/testdata/valid-files/resources.tf b/configs/testdata/valid-files/resources.tf similarity index 100% rename from internal/configs/testdata/valid-files/resources.tf rename to configs/testdata/valid-files/resources.tf diff --git a/internal/configs/testdata/valid-files/resources.tf.json b/configs/testdata/valid-files/resources.tf.json similarity index 100% rename from internal/configs/testdata/valid-files/resources.tf.json rename to configs/testdata/valid-files/resources.tf.json diff --git a/internal/configs/testdata/valid-files/valid-language-edition.tf b/configs/testdata/valid-files/valid-language-edition.tf similarity index 100% rename from internal/configs/testdata/valid-files/valid-language-edition.tf rename to configs/testdata/valid-files/valid-language-edition.tf diff --git a/internal/configs/testdata/valid-files/variable_validation.tf b/configs/testdata/valid-files/variable_validation.tf similarity index 100% rename from internal/configs/testdata/valid-files/variable_validation.tf rename to configs/testdata/valid-files/variable_validation.tf diff --git a/internal/configs/testdata/valid-files/variables.tf b/configs/testdata/valid-files/variables.tf similarity index 100% rename from internal/configs/testdata/valid-files/variables.tf rename to configs/testdata/valid-files/variables.tf diff --git a/internal/configs/testdata/valid-files/variables.tf.json b/configs/testdata/valid-files/variables.tf.json similarity index 100% rename from internal/configs/testdata/valid-files/variables.tf.json rename to configs/testdata/valid-files/variables.tf.json diff --git a/internal/configs/testdata/valid-modules/empty/README b/configs/testdata/valid-modules/empty/README similarity index 100% rename from internal/configs/testdata/valid-modules/empty/README rename to configs/testdata/valid-modules/empty/README diff --git a/internal/configs/testdata/valid-modules/implied-providers/providers.tf b/configs/testdata/valid-modules/implied-providers/providers.tf similarity index 100% rename from internal/configs/testdata/valid-modules/implied-providers/providers.tf rename to configs/testdata/valid-modules/implied-providers/providers.tf diff --git a/internal/configs/testdata/valid-modules/implied-providers/resources.tf b/configs/testdata/valid-modules/implied-providers/resources.tf similarity index 100% rename from internal/configs/testdata/valid-modules/implied-providers/resources.tf rename to configs/testdata/valid-modules/implied-providers/resources.tf diff --git a/internal/configs/testdata/valid-modules/moved-blocks/moved-blocks-1.tf b/configs/testdata/valid-modules/moved-blocks/moved-blocks-1.tf similarity index 100% rename from internal/configs/testdata/valid-modules/moved-blocks/moved-blocks-1.tf rename to configs/testdata/valid-modules/moved-blocks/moved-blocks-1.tf diff --git a/internal/configs/testdata/valid-modules/moved-blocks/moved-blocks-2.tf b/configs/testdata/valid-modules/moved-blocks/moved-blocks-2.tf similarity index 100% rename from internal/configs/testdata/valid-modules/moved-blocks/moved-blocks-2.tf rename to configs/testdata/valid-modules/moved-blocks/moved-blocks-2.tf diff --git a/internal/configs/testdata/valid-modules/nested-providers-fqns/child/main.tf b/configs/testdata/valid-modules/nested-providers-fqns/child/main.tf similarity index 100% rename from internal/configs/testdata/valid-modules/nested-providers-fqns/child/main.tf rename to configs/testdata/valid-modules/nested-providers-fqns/child/main.tf diff --git a/internal/configs/testdata/valid-modules/nested-providers-fqns/main.tf b/configs/testdata/valid-modules/nested-providers-fqns/main.tf similarity index 100% rename from internal/configs/testdata/valid-modules/nested-providers-fqns/main.tf rename to configs/testdata/valid-modules/nested-providers-fqns/main.tf diff --git a/internal/configs/testdata/valid-modules/override-backend-no-base/main.tf b/configs/testdata/valid-modules/override-backend-no-base/main.tf similarity index 100% rename from internal/configs/testdata/valid-modules/override-backend-no-base/main.tf rename to configs/testdata/valid-modules/override-backend-no-base/main.tf diff --git a/internal/configs/testdata/valid-modules/override-backend-no-base/override.tf b/configs/testdata/valid-modules/override-backend-no-base/override.tf similarity index 100% rename from internal/configs/testdata/valid-modules/override-backend-no-base/override.tf rename to configs/testdata/valid-modules/override-backend-no-base/override.tf diff --git a/internal/configs/testdata/valid-modules/override-backend-with-cloud/main.tf b/configs/testdata/valid-modules/override-backend-with-cloud/main.tf similarity index 100% rename from internal/configs/testdata/valid-modules/override-backend-with-cloud/main.tf rename to configs/testdata/valid-modules/override-backend-with-cloud/main.tf diff --git a/internal/configs/testdata/valid-modules/override-backend-with-cloud/override.tf b/configs/testdata/valid-modules/override-backend-with-cloud/override.tf similarity index 100% rename from internal/configs/testdata/valid-modules/override-backend-with-cloud/override.tf rename to configs/testdata/valid-modules/override-backend-with-cloud/override.tf diff --git a/internal/configs/testdata/valid-modules/override-backend/main.tf b/configs/testdata/valid-modules/override-backend/main.tf similarity index 100% rename from internal/configs/testdata/valid-modules/override-backend/main.tf rename to configs/testdata/valid-modules/override-backend/main.tf diff --git a/internal/configs/testdata/valid-modules/override-backend/override.tf b/configs/testdata/valid-modules/override-backend/override.tf similarity index 100% rename from internal/configs/testdata/valid-modules/override-backend/override.tf rename to configs/testdata/valid-modules/override-backend/override.tf diff --git a/internal/configs/testdata/valid-modules/override-cloud-no-base/main.tf b/configs/testdata/valid-modules/override-cloud-no-base/main.tf similarity index 100% rename from internal/configs/testdata/valid-modules/override-cloud-no-base/main.tf rename to configs/testdata/valid-modules/override-cloud-no-base/main.tf diff --git a/internal/configs/testdata/valid-modules/override-cloud-no-base/override.tf b/configs/testdata/valid-modules/override-cloud-no-base/override.tf similarity index 100% rename from internal/configs/testdata/valid-modules/override-cloud-no-base/override.tf rename to configs/testdata/valid-modules/override-cloud-no-base/override.tf diff --git a/internal/configs/testdata/valid-modules/override-cloud/main.tf b/configs/testdata/valid-modules/override-cloud/main.tf similarity index 100% rename from internal/configs/testdata/valid-modules/override-cloud/main.tf rename to configs/testdata/valid-modules/override-cloud/main.tf diff --git a/internal/configs/testdata/valid-modules/override-cloud/override.tf b/configs/testdata/valid-modules/override-cloud/override.tf similarity index 100% rename from internal/configs/testdata/valid-modules/override-cloud/override.tf rename to configs/testdata/valid-modules/override-cloud/override.tf diff --git a/internal/configs/testdata/valid-modules/override-dynamic-block-base/a_override.tf b/configs/testdata/valid-modules/override-dynamic-block-base/a_override.tf similarity index 100% rename from internal/configs/testdata/valid-modules/override-dynamic-block-base/a_override.tf rename to configs/testdata/valid-modules/override-dynamic-block-base/a_override.tf diff --git a/internal/configs/testdata/valid-modules/override-dynamic-block-base/base.tf b/configs/testdata/valid-modules/override-dynamic-block-base/base.tf similarity index 100% rename from internal/configs/testdata/valid-modules/override-dynamic-block-base/base.tf rename to configs/testdata/valid-modules/override-dynamic-block-base/base.tf diff --git a/internal/configs/testdata/valid-modules/override-dynamic-block-override/a_override.tf b/configs/testdata/valid-modules/override-dynamic-block-override/a_override.tf similarity index 100% rename from internal/configs/testdata/valid-modules/override-dynamic-block-override/a_override.tf rename to configs/testdata/valid-modules/override-dynamic-block-override/a_override.tf diff --git a/internal/configs/testdata/valid-modules/override-dynamic-block-override/base.tf b/configs/testdata/valid-modules/override-dynamic-block-override/base.tf similarity index 100% rename from internal/configs/testdata/valid-modules/override-dynamic-block-override/base.tf rename to configs/testdata/valid-modules/override-dynamic-block-override/base.tf diff --git a/internal/configs/testdata/valid-modules/override-ignore-changes/main.tf b/configs/testdata/valid-modules/override-ignore-changes/main.tf similarity index 100% rename from internal/configs/testdata/valid-modules/override-ignore-changes/main.tf rename to configs/testdata/valid-modules/override-ignore-changes/main.tf diff --git a/internal/configs/testdata/valid-modules/override-ignore-changes/main_override.tf b/configs/testdata/valid-modules/override-ignore-changes/main_override.tf similarity index 100% rename from internal/configs/testdata/valid-modules/override-ignore-changes/main_override.tf rename to configs/testdata/valid-modules/override-ignore-changes/main_override.tf diff --git a/internal/configs/testdata/valid-modules/override-module/a_override.tf b/configs/testdata/valid-modules/override-module/a_override.tf similarity index 100% rename from internal/configs/testdata/valid-modules/override-module/a_override.tf rename to configs/testdata/valid-modules/override-module/a_override.tf diff --git a/internal/configs/testdata/valid-modules/override-module/b_override.tf b/configs/testdata/valid-modules/override-module/b_override.tf similarity index 100% rename from internal/configs/testdata/valid-modules/override-module/b_override.tf rename to configs/testdata/valid-modules/override-module/b_override.tf diff --git a/internal/configs/testdata/valid-modules/override-module/primary.tf b/configs/testdata/valid-modules/override-module/primary.tf similarity index 100% rename from internal/configs/testdata/valid-modules/override-module/primary.tf rename to configs/testdata/valid-modules/override-module/primary.tf diff --git a/internal/configs/testdata/valid-modules/override-output-sensitive/override.tf b/configs/testdata/valid-modules/override-output-sensitive/override.tf similarity index 100% rename from internal/configs/testdata/valid-modules/override-output-sensitive/override.tf rename to configs/testdata/valid-modules/override-output-sensitive/override.tf diff --git a/internal/configs/testdata/valid-modules/override-output-sensitive/primary.tf b/configs/testdata/valid-modules/override-output-sensitive/primary.tf similarity index 100% rename from internal/configs/testdata/valid-modules/override-output-sensitive/primary.tf rename to configs/testdata/valid-modules/override-output-sensitive/primary.tf diff --git a/internal/configs/testdata/valid-modules/override-resource-provider/a_override.tf b/configs/testdata/valid-modules/override-resource-provider/a_override.tf similarity index 100% rename from internal/configs/testdata/valid-modules/override-resource-provider/a_override.tf rename to configs/testdata/valid-modules/override-resource-provider/a_override.tf diff --git a/internal/configs/testdata/valid-modules/override-resource-provider/base.tf b/configs/testdata/valid-modules/override-resource-provider/base.tf similarity index 100% rename from internal/configs/testdata/valid-modules/override-resource-provider/base.tf rename to configs/testdata/valid-modules/override-resource-provider/base.tf diff --git a/internal/configs/testdata/valid-modules/override-variable-sensitive/a_override.tf b/configs/testdata/valid-modules/override-variable-sensitive/a_override.tf similarity index 100% rename from internal/configs/testdata/valid-modules/override-variable-sensitive/a_override.tf rename to configs/testdata/valid-modules/override-variable-sensitive/a_override.tf diff --git a/internal/configs/testdata/valid-modules/override-variable-sensitive/b_override.tf b/configs/testdata/valid-modules/override-variable-sensitive/b_override.tf similarity index 100% rename from internal/configs/testdata/valid-modules/override-variable-sensitive/b_override.tf rename to configs/testdata/valid-modules/override-variable-sensitive/b_override.tf diff --git a/internal/configs/testdata/valid-modules/override-variable-sensitive/primary.tf b/configs/testdata/valid-modules/override-variable-sensitive/primary.tf similarity index 100% rename from internal/configs/testdata/valid-modules/override-variable-sensitive/primary.tf rename to configs/testdata/valid-modules/override-variable-sensitive/primary.tf diff --git a/internal/configs/testdata/valid-modules/override-variable/a_override.tf b/configs/testdata/valid-modules/override-variable/a_override.tf similarity index 100% rename from internal/configs/testdata/valid-modules/override-variable/a_override.tf rename to configs/testdata/valid-modules/override-variable/a_override.tf diff --git a/internal/configs/testdata/valid-modules/override-variable/b_override.tf b/configs/testdata/valid-modules/override-variable/b_override.tf similarity index 100% rename from internal/configs/testdata/valid-modules/override-variable/b_override.tf rename to configs/testdata/valid-modules/override-variable/b_override.tf diff --git a/internal/configs/testdata/valid-modules/override-variable/primary.tf b/configs/testdata/valid-modules/override-variable/primary.tf similarity index 100% rename from internal/configs/testdata/valid-modules/override-variable/primary.tf rename to configs/testdata/valid-modules/override-variable/primary.tf diff --git a/internal/configs/testdata/valid-modules/provider-aliases/main.tf b/configs/testdata/valid-modules/provider-aliases/main.tf similarity index 100% rename from internal/configs/testdata/valid-modules/provider-aliases/main.tf rename to configs/testdata/valid-modules/provider-aliases/main.tf diff --git a/internal/configs/testdata/valid-modules/provider-meta/main.tf b/configs/testdata/valid-modules/provider-meta/main.tf similarity index 100% rename from internal/configs/testdata/valid-modules/provider-meta/main.tf rename to configs/testdata/valid-modules/provider-meta/main.tf diff --git a/internal/configs/testdata/valid-modules/providers-fqns/main.tf b/configs/testdata/valid-modules/providers-fqns/main.tf similarity index 100% rename from internal/configs/testdata/valid-modules/providers-fqns/main.tf rename to configs/testdata/valid-modules/providers-fqns/main.tf diff --git a/internal/configs/testdata/valid-modules/required-providers-after-resource/main.tf b/configs/testdata/valid-modules/required-providers-after-resource/main.tf similarity index 100% rename from internal/configs/testdata/valid-modules/required-providers-after-resource/main.tf rename to configs/testdata/valid-modules/required-providers-after-resource/main.tf diff --git a/internal/configs/testdata/valid-modules/required-providers-after-resource/providers.tf b/configs/testdata/valid-modules/required-providers-after-resource/providers.tf similarity index 100% rename from internal/configs/testdata/valid-modules/required-providers-after-resource/providers.tf rename to configs/testdata/valid-modules/required-providers-after-resource/providers.tf diff --git a/internal/configs/testdata/valid-modules/required-providers-overrides/bar_provider_override.tf b/configs/testdata/valid-modules/required-providers-overrides/bar_provider_override.tf similarity index 100% rename from internal/configs/testdata/valid-modules/required-providers-overrides/bar_provider_override.tf rename to configs/testdata/valid-modules/required-providers-overrides/bar_provider_override.tf diff --git a/internal/configs/testdata/valid-modules/required-providers-overrides/main.tf b/configs/testdata/valid-modules/required-providers-overrides/main.tf similarity index 100% rename from internal/configs/testdata/valid-modules/required-providers-overrides/main.tf rename to configs/testdata/valid-modules/required-providers-overrides/main.tf diff --git a/internal/configs/testdata/valid-modules/required-providers-overrides/providers.tf b/configs/testdata/valid-modules/required-providers-overrides/providers.tf similarity index 100% rename from internal/configs/testdata/valid-modules/required-providers-overrides/providers.tf rename to configs/testdata/valid-modules/required-providers-overrides/providers.tf diff --git a/internal/configs/testdata/warning-files/depends_on.tf b/configs/testdata/warning-files/depends_on.tf similarity index 100% rename from internal/configs/testdata/warning-files/depends_on.tf rename to configs/testdata/warning-files/depends_on.tf diff --git a/internal/configs/testdata/warning-files/provider_ref.tf b/configs/testdata/warning-files/provider_ref.tf similarity index 100% rename from internal/configs/testdata/warning-files/provider_ref.tf rename to configs/testdata/warning-files/provider_ref.tf diff --git a/internal/configs/testdata/warning-files/provisioner_keyword.tf b/configs/testdata/warning-files/provisioner_keyword.tf similarity index 100% rename from internal/configs/testdata/warning-files/provisioner_keyword.tf rename to configs/testdata/warning-files/provisioner_keyword.tf diff --git a/internal/configs/util.go b/configs/util.go similarity index 100% rename from internal/configs/util.go rename to configs/util.go diff --git a/internal/configs/variable_type_hint.go b/configs/variable_type_hint.go similarity index 100% rename from internal/configs/variable_type_hint.go rename to configs/variable_type_hint.go diff --git a/internal/configs/variabletypehint_string.go b/configs/variabletypehint_string.go similarity index 100% rename from internal/configs/variabletypehint_string.go rename to configs/variabletypehint_string.go diff --git a/internal/configs/version_constraint.go b/configs/version_constraint.go similarity index 100% rename from internal/configs/version_constraint.go rename to configs/version_constraint.go diff --git a/internal/copy/copy_dir.go b/copy/copy_dir.go similarity index 100% rename from internal/copy/copy_dir.go rename to copy/copy_dir.go diff --git a/internal/copy/copy_dir_test.go b/copy/copy_dir_test.go similarity index 100% rename from internal/copy/copy_dir_test.go rename to copy/copy_dir_test.go diff --git a/internal/copy/copy_file.go b/copy/copy_file.go similarity index 100% rename from internal/copy/copy_file.go rename to copy/copy_file.go diff --git a/internal/dag/dag.go b/dag/dag.go similarity index 99% rename from internal/dag/dag.go rename to dag/dag.go index 362c847f3d9f..d375d5f09363 100644 --- a/internal/dag/dag.go +++ b/dag/dag.go @@ -5,7 +5,7 @@ import ( "sort" "strings" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" "github.com/hashicorp/go-multierror" ) diff --git a/internal/dag/dag_test.go b/dag/dag_test.go similarity index 99% rename from internal/dag/dag_test.go rename to dag/dag_test.go index 5b273938e8fe..5a36564a3dad 100644 --- a/internal/dag/dag_test.go +++ b/dag/dag_test.go @@ -10,9 +10,9 @@ import ( "sync" "testing" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" - _ "github.com/hashicorp/terraform/internal/logging" + _ "github.com/hashicorp/terraform/logging" ) func TestMain(m *testing.M) { diff --git a/internal/dag/dot.go b/dag/dot.go similarity index 100% rename from internal/dag/dot.go rename to dag/dot.go diff --git a/internal/dag/dot_test.go b/dag/dot_test.go similarity index 100% rename from internal/dag/dot_test.go rename to dag/dot_test.go diff --git a/internal/dag/edge.go b/dag/edge.go similarity index 100% rename from internal/dag/edge.go rename to dag/edge.go diff --git a/internal/dag/edge_test.go b/dag/edge_test.go similarity index 100% rename from internal/dag/edge_test.go rename to dag/edge_test.go diff --git a/internal/dag/graph.go b/dag/graph.go similarity index 100% rename from internal/dag/graph.go rename to dag/graph.go diff --git a/internal/dag/graph_test.go b/dag/graph_test.go similarity index 100% rename from internal/dag/graph_test.go rename to dag/graph_test.go diff --git a/internal/dag/marshal.go b/dag/marshal.go similarity index 100% rename from internal/dag/marshal.go rename to dag/marshal.go diff --git a/internal/dag/marshal_test.go b/dag/marshal_test.go similarity index 100% rename from internal/dag/marshal_test.go rename to dag/marshal_test.go diff --git a/internal/dag/set.go b/dag/set.go similarity index 100% rename from internal/dag/set.go rename to dag/set.go diff --git a/internal/dag/set_test.go b/dag/set_test.go similarity index 100% rename from internal/dag/set_test.go rename to dag/set_test.go diff --git a/internal/dag/tarjan.go b/dag/tarjan.go similarity index 100% rename from internal/dag/tarjan.go rename to dag/tarjan.go diff --git a/internal/dag/tarjan_test.go b/dag/tarjan_test.go similarity index 100% rename from internal/dag/tarjan_test.go rename to dag/tarjan_test.go diff --git a/internal/dag/walk.go b/dag/walk.go similarity index 99% rename from internal/dag/walk.go rename to dag/walk.go index ff8afeac7c13..26b249230f33 100644 --- a/internal/dag/walk.go +++ b/dag/walk.go @@ -6,7 +6,7 @@ import ( "sync" "time" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" ) // Walker is used to walk every vertex of a graph in parallel. diff --git a/internal/dag/walk_test.go b/dag/walk_test.go similarity index 99% rename from internal/dag/walk_test.go rename to dag/walk_test.go index fc5844e2e154..5464248b13da 100644 --- a/internal/dag/walk_test.go +++ b/dag/walk_test.go @@ -7,7 +7,7 @@ import ( "testing" "time" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" ) func TestWalker_basic(t *testing.T) { diff --git a/internal/depsfile/doc.go b/depsfile/doc.go similarity index 100% rename from internal/depsfile/doc.go rename to depsfile/doc.go diff --git a/internal/depsfile/locks.go b/depsfile/locks.go similarity index 99% rename from internal/depsfile/locks.go rename to depsfile/locks.go index 4997c4858f2b..fc84193baa08 100644 --- a/internal/depsfile/locks.go +++ b/depsfile/locks.go @@ -4,8 +4,8 @@ import ( "fmt" "sort" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/getproviders" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/getproviders" ) // Locks is the top-level type representing the information retained in a diff --git a/internal/depsfile/locks_file.go b/depsfile/locks_file.go similarity index 98% rename from internal/depsfile/locks_file.go rename to depsfile/locks_file.go index e619e06703c6..d9ad3552f861 100644 --- a/internal/depsfile/locks_file.go +++ b/depsfile/locks_file.go @@ -11,10 +11,10 @@ import ( "github.com/hashicorp/hcl/v2/hclwrite" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/getproviders" - "github.com/hashicorp/terraform/internal/replacefile" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/getproviders" + "github.com/hashicorp/terraform/replacefile" + "github.com/hashicorp/terraform/tfdiags" "github.com/hashicorp/terraform/version" ) diff --git a/internal/depsfile/locks_file_test.go b/depsfile/locks_file_test.go similarity index 98% rename from internal/depsfile/locks_file_test.go rename to depsfile/locks_file_test.go index 632aa71c7a07..21c08dda85b5 100644 --- a/internal/depsfile/locks_file_test.go +++ b/depsfile/locks_file_test.go @@ -9,9 +9,9 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/getproviders" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/getproviders" + "github.com/hashicorp/terraform/tfdiags" ) func TestLoadLocksFromFile(t *testing.T) { diff --git a/internal/depsfile/locks_test.go b/depsfile/locks_test.go similarity index 98% rename from internal/depsfile/locks_test.go rename to depsfile/locks_test.go index ce84d2e2e003..316e406eed36 100644 --- a/internal/depsfile/locks_test.go +++ b/depsfile/locks_test.go @@ -4,8 +4,8 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/getproviders" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/getproviders" ) func TestLocksEqual(t *testing.T) { diff --git a/internal/depsfile/paths.go b/depsfile/paths.go similarity index 100% rename from internal/depsfile/paths.go rename to depsfile/paths.go diff --git a/internal/depsfile/testdata/locks-files/empty.hcl b/depsfile/testdata/locks-files/empty.hcl similarity index 100% rename from internal/depsfile/testdata/locks-files/empty.hcl rename to depsfile/testdata/locks-files/empty.hcl diff --git a/internal/depsfile/testdata/locks-files/invalid-provider-addrs.hcl b/depsfile/testdata/locks-files/invalid-provider-addrs.hcl similarity index 100% rename from internal/depsfile/testdata/locks-files/invalid-provider-addrs.hcl rename to depsfile/testdata/locks-files/invalid-provider-addrs.hcl diff --git a/internal/depsfile/testdata/locks-files/invalid-versions.hcl b/depsfile/testdata/locks-files/invalid-versions.hcl similarity index 100% rename from internal/depsfile/testdata/locks-files/invalid-versions.hcl rename to depsfile/testdata/locks-files/invalid-versions.hcl diff --git a/internal/depsfile/testdata/locks-files/unsupported-block.hcl b/depsfile/testdata/locks-files/unsupported-block.hcl similarity index 100% rename from internal/depsfile/testdata/locks-files/unsupported-block.hcl rename to depsfile/testdata/locks-files/unsupported-block.hcl diff --git a/internal/depsfile/testdata/locks-files/valid-provider-locks.hcl b/depsfile/testdata/locks-files/valid-provider-locks.hcl similarity index 100% rename from internal/depsfile/testdata/locks-files/valid-provider-locks.hcl rename to depsfile/testdata/locks-files/valid-provider-locks.hcl diff --git a/internal/depsfile/testing.go b/depsfile/testing.go similarity index 100% rename from internal/depsfile/testing.go rename to depsfile/testing.go diff --git a/internal/didyoumean/name_suggestion.go b/didyoumean/name_suggestion.go similarity index 100% rename from internal/didyoumean/name_suggestion.go rename to didyoumean/name_suggestion.go diff --git a/internal/didyoumean/name_suggestion_test.go b/didyoumean/name_suggestion_test.go similarity index 100% rename from internal/didyoumean/name_suggestion_test.go rename to didyoumean/name_suggestion_test.go diff --git a/internal/e2e/e2e.go b/e2e/e2e.go similarity index 97% rename from internal/e2e/e2e.go rename to e2e/e2e.go index efdd2489a385..8167e412632c 100644 --- a/internal/e2e/e2e.go +++ b/e2e/e2e.go @@ -10,10 +10,10 @@ import ( "path/filepath" "testing" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/plans/planfile" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/statefile" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/plans/planfile" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/statefile" ) // Type binary represents the combination of a compiled binary diff --git a/internal/earlyconfig/config.go b/earlyconfig/config.go similarity index 96% rename from internal/earlyconfig/config.go rename to earlyconfig/config.go index 86d93c27ba6d..e5361f38ee03 100644 --- a/internal/earlyconfig/config.go +++ b/earlyconfig/config.go @@ -6,11 +6,11 @@ import ( version "github.com/hashicorp/go-version" "github.com/hashicorp/terraform-config-inspect/tfconfig" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/getproviders" - "github.com/hashicorp/terraform/internal/moduledeps" - "github.com/hashicorp/terraform/internal/plugin/discovery" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/getproviders" + "github.com/hashicorp/terraform/moduledeps" + "github.com/hashicorp/terraform/plugin/discovery" + "github.com/hashicorp/terraform/tfdiags" ) // A Config is a node in the tree of modules within a configuration. diff --git a/internal/earlyconfig/config_build.go b/earlyconfig/config_build.go similarity index 98% rename from internal/earlyconfig/config_build.go rename to earlyconfig/config_build.go index dd84cf9cccbf..cd100fe7fa87 100644 --- a/internal/earlyconfig/config_build.go +++ b/earlyconfig/config_build.go @@ -7,8 +7,8 @@ import ( version "github.com/hashicorp/go-version" "github.com/hashicorp/terraform-config-inspect/tfconfig" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/tfdiags" ) // BuildConfig constructs a Config from a root module by loading all of its diff --git a/internal/earlyconfig/config_test.go b/earlyconfig/config_test.go similarity index 94% rename from internal/earlyconfig/config_test.go rename to earlyconfig/config_test.go index 21aa71beeabf..cd0e85193d6b 100644 --- a/internal/earlyconfig/config_test.go +++ b/earlyconfig/config_test.go @@ -9,9 +9,9 @@ import ( version "github.com/hashicorp/go-version" "github.com/hashicorp/terraform-config-inspect/tfconfig" svchost "github.com/hashicorp/terraform-svchost" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/getproviders" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/getproviders" + "github.com/hashicorp/terraform/tfdiags" ) func TestConfigProviderRequirements(t *testing.T) { diff --git a/internal/earlyconfig/diagnostics.go b/earlyconfig/diagnostics.go similarity index 97% rename from internal/earlyconfig/diagnostics.go rename to earlyconfig/diagnostics.go index 15adad56385a..fd451f71df37 100644 --- a/internal/earlyconfig/diagnostics.go +++ b/earlyconfig/diagnostics.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/hashicorp/terraform-config-inspect/tfconfig" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" ) func wrapDiagnostics(diags tfconfig.Diagnostics) tfdiags.Diagnostics { diff --git a/internal/earlyconfig/doc.go b/earlyconfig/doc.go similarity index 100% rename from internal/earlyconfig/doc.go rename to earlyconfig/doc.go diff --git a/internal/earlyconfig/module.go b/earlyconfig/module.go similarity index 86% rename from internal/earlyconfig/module.go rename to earlyconfig/module.go index e4edba0e0582..d2d628797ae0 100644 --- a/internal/earlyconfig/module.go +++ b/earlyconfig/module.go @@ -2,7 +2,7 @@ package earlyconfig import ( "github.com/hashicorp/terraform-config-inspect/tfconfig" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" ) // LoadModule loads some top-level metadata for the module in the given diff --git a/internal/earlyconfig/testdata/provider-reqs/child/provider-reqs-child.tf b/earlyconfig/testdata/provider-reqs/child/provider-reqs-child.tf similarity index 100% rename from internal/earlyconfig/testdata/provider-reqs/child/provider-reqs-child.tf rename to earlyconfig/testdata/provider-reqs/child/provider-reqs-child.tf diff --git a/internal/earlyconfig/testdata/provider-reqs/provider-reqs-root.tf b/earlyconfig/testdata/provider-reqs/provider-reqs-root.tf similarity index 100% rename from internal/earlyconfig/testdata/provider-reqs/provider-reqs-root.tf rename to earlyconfig/testdata/provider-reqs/provider-reqs-root.tf diff --git a/internal/experiments/doc.go b/experiments/doc.go similarity index 100% rename from internal/experiments/doc.go rename to experiments/doc.go diff --git a/internal/experiments/errors.go b/experiments/errors.go similarity index 100% rename from internal/experiments/errors.go rename to experiments/errors.go diff --git a/internal/experiments/experiment.go b/experiments/experiment.go similarity index 100% rename from internal/experiments/experiment.go rename to experiments/experiment.go diff --git a/internal/experiments/set.go b/experiments/set.go similarity index 100% rename from internal/experiments/set.go rename to experiments/set.go diff --git a/internal/experiments/testing.go b/experiments/testing.go similarity index 100% rename from internal/experiments/testing.go rename to experiments/testing.go diff --git a/internal/getmodules/doc.go b/getmodules/doc.go similarity index 100% rename from internal/getmodules/doc.go rename to getmodules/doc.go diff --git a/internal/getmodules/file_detector.go b/getmodules/file_detector.go similarity index 100% rename from internal/getmodules/file_detector.go rename to getmodules/file_detector.go diff --git a/internal/getmodules/getter.go b/getmodules/getter.go similarity index 99% rename from internal/getmodules/getter.go rename to getmodules/getter.go index 82ea599afcb9..70f2cd88df7d 100644 --- a/internal/getmodules/getter.go +++ b/getmodules/getter.go @@ -8,7 +8,7 @@ import ( cleanhttp "github.com/hashicorp/go-cleanhttp" getter "github.com/hashicorp/go-getter" - "github.com/hashicorp/terraform/internal/copy" + "github.com/hashicorp/terraform/copy" ) // We configure our own go-getter detector and getter sets here, because diff --git a/internal/getmodules/installer.go b/getmodules/installer.go similarity index 100% rename from internal/getmodules/installer.go rename to getmodules/installer.go diff --git a/internal/getmodules/package.go b/getmodules/package.go similarity index 100% rename from internal/getmodules/package.go rename to getmodules/package.go diff --git a/internal/getmodules/subdir.go b/getmodules/subdir.go similarity index 100% rename from internal/getmodules/subdir.go rename to getmodules/subdir.go diff --git a/internal/getproviders/didyoumean.go b/getproviders/didyoumean.go similarity index 99% rename from internal/getproviders/didyoumean.go rename to getproviders/didyoumean.go index e31ba20e4195..f23fedbebe64 100644 --- a/internal/getproviders/didyoumean.go +++ b/getproviders/didyoumean.go @@ -11,7 +11,7 @@ import ( "github.com/hashicorp/go-retryablehttp" svchost "github.com/hashicorp/terraform-svchost" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) // MissingProviderSuggestion takes a provider address that failed installation diff --git a/internal/getproviders/didyoumean_test.go b/getproviders/didyoumean_test.go similarity index 99% rename from internal/getproviders/didyoumean_test.go rename to getproviders/didyoumean_test.go index 18804a9a6f39..85bc4582cbc2 100644 --- a/internal/getproviders/didyoumean_test.go +++ b/getproviders/didyoumean_test.go @@ -5,7 +5,7 @@ import ( "testing" svchost "github.com/hashicorp/terraform-svchost" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) func TestMissingProviderSuggestion(t *testing.T) { diff --git a/internal/getproviders/doc.go b/getproviders/doc.go similarity index 100% rename from internal/getproviders/doc.go rename to getproviders/doc.go diff --git a/internal/getproviders/errors.go b/getproviders/errors.go similarity index 99% rename from internal/getproviders/errors.go rename to getproviders/errors.go index 7d2720c0f8cf..7ff7f39c0a2c 100644 --- a/internal/getproviders/errors.go +++ b/getproviders/errors.go @@ -6,7 +6,7 @@ import ( svchost "github.com/hashicorp/terraform-svchost" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) // ErrHostNoProviders is an error type used to indicate that a hostname given diff --git a/internal/getproviders/filesystem_mirror_source.go b/getproviders/filesystem_mirror_source.go similarity index 98% rename from internal/getproviders/filesystem_mirror_source.go rename to getproviders/filesystem_mirror_source.go index 118aff208f32..b611a5666137 100644 --- a/internal/getproviders/filesystem_mirror_source.go +++ b/getproviders/filesystem_mirror_source.go @@ -3,7 +3,7 @@ package getproviders import ( "context" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) // FilesystemMirrorSource is a source that reads providers and their metadata diff --git a/internal/getproviders/filesystem_mirror_source_test.go b/getproviders/filesystem_mirror_source_test.go similarity index 99% rename from internal/getproviders/filesystem_mirror_source_test.go rename to getproviders/filesystem_mirror_source_test.go index f498b81cc4e3..ea73eefe4a28 100644 --- a/internal/getproviders/filesystem_mirror_source_test.go +++ b/getproviders/filesystem_mirror_source_test.go @@ -8,7 +8,7 @@ import ( "github.com/google/go-cmp/cmp" svchost "github.com/hashicorp/terraform-svchost" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) func TestFilesystemMirrorSourceAllAvailablePackages(t *testing.T) { diff --git a/internal/getproviders/filesystem_search.go b/getproviders/filesystem_search.go similarity index 99% rename from internal/getproviders/filesystem_search.go rename to getproviders/filesystem_search.go index 2ae727293fea..690c79f5efb1 100644 --- a/internal/getproviders/filesystem_search.go +++ b/getproviders/filesystem_search.go @@ -9,7 +9,7 @@ import ( svchost "github.com/hashicorp/terraform-svchost" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) // SearchLocalDirectory performs an immediate, one-off scan of the given base diff --git a/internal/getproviders/filesystem_search_test.go b/getproviders/filesystem_search_test.go similarity index 96% rename from internal/getproviders/filesystem_search_test.go rename to getproviders/filesystem_search_test.go index 37ced6ff5966..8577065569ed 100644 --- a/internal/getproviders/filesystem_search_test.go +++ b/getproviders/filesystem_search_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) func TestSearchLocalDirectory(t *testing.T) { diff --git a/internal/getproviders/hanging_source.go b/getproviders/hanging_source.go similarity index 93% rename from internal/getproviders/hanging_source.go rename to getproviders/hanging_source.go index 388b617013f2..f0ae802a4ebf 100644 --- a/internal/getproviders/hanging_source.go +++ b/getproviders/hanging_source.go @@ -3,7 +3,7 @@ package getproviders import ( "context" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) // HangingSource is an implementation of Source which hangs until the given diff --git a/internal/getproviders/hash.go b/getproviders/hash.go similarity index 100% rename from internal/getproviders/hash.go rename to getproviders/hash.go diff --git a/internal/getproviders/hash_test.go b/getproviders/hash_test.go similarity index 100% rename from internal/getproviders/hash_test.go rename to getproviders/hash_test.go diff --git a/internal/getproviders/http_mirror_source.go b/getproviders/http_mirror_source.go similarity index 98% rename from internal/getproviders/http_mirror_source.go rename to getproviders/http_mirror_source.go index 82f890a763fc..ccca3b95d6a0 100644 --- a/internal/getproviders/http_mirror_source.go +++ b/getproviders/http_mirror_source.go @@ -17,9 +17,9 @@ import ( svcauth "github.com/hashicorp/terraform-svchost/auth" "golang.org/x/net/idna" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/httpclient" - "github.com/hashicorp/terraform/internal/logging" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/httpclient" + "github.com/hashicorp/terraform/logging" "github.com/hashicorp/terraform/version" ) diff --git a/internal/getproviders/http_mirror_source_test.go b/getproviders/http_mirror_source_test.go similarity index 99% rename from internal/getproviders/http_mirror_source_test.go rename to getproviders/http_mirror_source_test.go index 3bf8a004aa5d..00aff1462c81 100644 --- a/internal/getproviders/http_mirror_source_test.go +++ b/getproviders/http_mirror_source_test.go @@ -12,7 +12,7 @@ import ( svchost "github.com/hashicorp/terraform-svchost" svcauth "github.com/hashicorp/terraform-svchost/auth" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) func TestHTTPMirrorSource(t *testing.T) { diff --git a/internal/getproviders/memoize_source.go b/getproviders/memoize_source.go similarity index 98% rename from internal/getproviders/memoize_source.go rename to getproviders/memoize_source.go index 2930d5a18d6d..942aa32d395a 100644 --- a/internal/getproviders/memoize_source.go +++ b/getproviders/memoize_source.go @@ -4,7 +4,7 @@ import ( "context" "sync" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) // MemoizeSource is a Source that wraps another Source and remembers its diff --git a/internal/getproviders/memoize_source_test.go b/getproviders/memoize_source_test.go similarity index 99% rename from internal/getproviders/memoize_source_test.go rename to getproviders/memoize_source_test.go index 006602b34554..ea331ea34604 100644 --- a/internal/getproviders/memoize_source_test.go +++ b/getproviders/memoize_source_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) func TestMemoizeSource(t *testing.T) { diff --git a/internal/getproviders/mock_source.go b/getproviders/mock_source.go similarity index 99% rename from internal/getproviders/mock_source.go rename to getproviders/mock_source.go index 930cbe313dde..32a99c1f19b3 100644 --- a/internal/getproviders/mock_source.go +++ b/getproviders/mock_source.go @@ -9,7 +9,7 @@ import ( "io/ioutil" "os" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) // MockSource is an in-memory-only, statically-configured source intended for diff --git a/internal/getproviders/multi_source.go b/getproviders/multi_source.go similarity index 99% rename from internal/getproviders/multi_source.go rename to getproviders/multi_source.go index bcec76e8ffb7..c347fbabd672 100644 --- a/internal/getproviders/multi_source.go +++ b/getproviders/multi_source.go @@ -7,7 +7,7 @@ import ( svchost "github.com/hashicorp/terraform-svchost" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) // MultiSource is a Source that wraps a series of other sources and combines diff --git a/internal/getproviders/multi_source_test.go b/getproviders/multi_source_test.go similarity index 99% rename from internal/getproviders/multi_source_test.go rename to getproviders/multi_source_test.go index f78fb519c572..027b80875e38 100644 --- a/internal/getproviders/multi_source_test.go +++ b/getproviders/multi_source_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) func TestMultiSourceAvailableVersions(t *testing.T) { diff --git a/internal/getproviders/package_authentication.go b/getproviders/package_authentication.go similarity index 100% rename from internal/getproviders/package_authentication.go rename to getproviders/package_authentication.go diff --git a/internal/getproviders/package_authentication_test.go b/getproviders/package_authentication_test.go similarity index 100% rename from internal/getproviders/package_authentication_test.go rename to getproviders/package_authentication_test.go diff --git a/internal/getproviders/public_keys.go b/getproviders/public_keys.go similarity index 100% rename from internal/getproviders/public_keys.go rename to getproviders/public_keys.go diff --git a/internal/getproviders/registry_client.go b/getproviders/registry_client.go similarity index 99% rename from internal/getproviders/registry_client.go rename to getproviders/registry_client.go index 5da2a83ca2b2..b0eec2d04157 100644 --- a/internal/getproviders/registry_client.go +++ b/getproviders/registry_client.go @@ -20,9 +20,9 @@ import ( svchost "github.com/hashicorp/terraform-svchost" svcauth "github.com/hashicorp/terraform-svchost/auth" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/httpclient" - "github.com/hashicorp/terraform/internal/logging" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/httpclient" + "github.com/hashicorp/terraform/logging" "github.com/hashicorp/terraform/version" ) diff --git a/internal/getproviders/registry_client_test.go b/getproviders/registry_client_test.go similarity index 99% rename from internal/getproviders/registry_client_test.go rename to getproviders/registry_client_test.go index 85fe00aa8f92..17d14f06efe9 100644 --- a/internal/getproviders/registry_client_test.go +++ b/getproviders/registry_client_test.go @@ -16,7 +16,7 @@ import ( "github.com/google/go-cmp/cmp" svchost "github.com/hashicorp/terraform-svchost" disco "github.com/hashicorp/terraform-svchost/disco" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) func TestConfigureDiscoveryRetry(t *testing.T) { diff --git a/internal/getproviders/registry_source.go b/getproviders/registry_source.go similarity index 99% rename from internal/getproviders/registry_source.go rename to getproviders/registry_source.go index e48e043f7161..e227438c599a 100644 --- a/internal/getproviders/registry_source.go +++ b/getproviders/registry_source.go @@ -7,7 +7,7 @@ import ( svchost "github.com/hashicorp/terraform-svchost" disco "github.com/hashicorp/terraform-svchost/disco" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) // RegistrySource is a Source that knows how to find and install providers from diff --git a/internal/getproviders/registry_source_test.go b/getproviders/registry_source_test.go similarity index 99% rename from internal/getproviders/registry_source_test.go rename to getproviders/registry_source_test.go index d55d1fff1a7a..b180c3b42c13 100644 --- a/internal/getproviders/registry_source_test.go +++ b/getproviders/registry_source_test.go @@ -11,7 +11,7 @@ import ( "github.com/google/go-cmp/cmp" svchost "github.com/hashicorp/terraform-svchost" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) func TestSourceAvailableVersions(t *testing.T) { diff --git a/internal/getproviders/source.go b/getproviders/source.go similarity index 89% rename from internal/getproviders/source.go rename to getproviders/source.go index b8543d8efd80..905bec6202eb 100644 --- a/internal/getproviders/source.go +++ b/getproviders/source.go @@ -3,7 +3,7 @@ package getproviders import ( "context" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) // A Source can query a particular source for information about providers diff --git a/internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/2.0.0/darwin_amd64/terraform-provider-null b/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/2.0.0/darwin_amd64/terraform-provider-null similarity index 100% rename from internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/2.0.0/darwin_amd64/terraform-provider-null rename to getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/2.0.0/darwin_amd64/terraform-provider-null diff --git a/internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/2.0.0/linux_amd64/terraform-provider-null b/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/2.0.0/linux_amd64/terraform-provider-null similarity index 100% rename from internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/2.0.0/linux_amd64/terraform-provider-null rename to getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/2.0.0/linux_amd64/terraform-provider-null diff --git a/internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/invalid b/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/invalid similarity index 100% rename from internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/invalid rename to getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/invalid diff --git a/internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip b/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip similarity index 100% rename from internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip rename to getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip diff --git a/internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/terraform-provider-null_invalid.zip b/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/terraform-provider-null_invalid.zip similarity index 100% rename from internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/terraform-provider-null_invalid.zip rename to getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/terraform-provider-null_invalid.zip diff --git a/internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/terraform-provider-null_invalid_invalid_invalid.zip b/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/terraform-provider-null_invalid_invalid_invalid.zip similarity index 100% rename from internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/terraform-provider-null_invalid_invalid_invalid.zip rename to getproviders/testdata/filesystem-mirror-invalid/hashicorp/null/terraform-provider-null_invalid_invalid_invalid.zip diff --git a/internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/random-beta/1.2.0/linux_amd64/terraform-provider-random-beta b/getproviders/testdata/filesystem-mirror-invalid/hashicorp/random-beta/1.2.0/linux_amd64/terraform-provider-random-beta similarity index 100% rename from internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/random-beta/1.2.0/linux_amd64/terraform-provider-random-beta rename to getproviders/testdata/filesystem-mirror-invalid/hashicorp/random-beta/1.2.0/linux_amd64/terraform-provider-random-beta diff --git a/internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/random/1.2.0/linux_amd64/terraform-provider-random b/getproviders/testdata/filesystem-mirror-invalid/hashicorp/random/1.2.0/linux_amd64/terraform-provider-random similarity index 100% rename from internal/getproviders/testdata/filesystem-mirror-invalid/hashicorp/random/1.2.0/linux_amd64/terraform-provider-random rename to getproviders/testdata/filesystem-mirror-invalid/hashicorp/random/1.2.0/linux_amd64/terraform-provider-random diff --git a/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/-/legacy/1.0.0/linux_amd64/terraform-provider-legacy b/getproviders/testdata/filesystem-mirror/registry.terraform.io/-/legacy/1.0.0/linux_amd64/terraform-provider-legacy similarity index 100% rename from internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/-/legacy/1.0.0/linux_amd64/terraform-provider-legacy rename to getproviders/testdata/filesystem-mirror/registry.terraform.io/-/legacy/1.0.0/linux_amd64/terraform-provider-legacy diff --git a/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/2.0.0/darwin_amd64/terraform-provider-null b/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/2.0.0/darwin_amd64/terraform-provider-null similarity index 100% rename from internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/2.0.0/darwin_amd64/terraform-provider-null rename to getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/2.0.0/darwin_amd64/terraform-provider-null diff --git a/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/2.0.0/linux_amd64/terraform-provider-null b/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/2.0.0/linux_amd64/terraform-provider-null similarity index 100% rename from internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/2.0.0/linux_amd64/terraform-provider-null rename to getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/2.0.0/linux_amd64/terraform-provider-null diff --git a/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/invalid b/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/invalid similarity index 100% rename from internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/invalid rename to getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/invalid diff --git a/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip b/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip similarity index 100% rename from internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip rename to getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip diff --git a/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/terraform-provider-null_invalid.zip b/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/terraform-provider-null_invalid.zip similarity index 100% rename from internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/terraform-provider-null_invalid.zip rename to getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/terraform-provider-null_invalid.zip diff --git a/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/terraform-provider-null_invalid_invalid_invalid.zip b/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/terraform-provider-null_invalid_invalid_invalid.zip similarity index 100% rename from internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/terraform-provider-null_invalid_invalid_invalid.zip rename to getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/terraform-provider-null_invalid_invalid_invalid.zip diff --git a/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/random-beta/1.2.0/linux_amd64/terraform-provider-random-beta b/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/random-beta/1.2.0/linux_amd64/terraform-provider-random-beta similarity index 100% rename from internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/random-beta/1.2.0/linux_amd64/terraform-provider-random-beta rename to getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/random-beta/1.2.0/linux_amd64/terraform-provider-random-beta diff --git a/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/random/1.2.0/linux_amd64/terraform-provider-random b/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/random/1.2.0/linux_amd64/terraform-provider-random similarity index 100% rename from internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/random/1.2.0/linux_amd64/terraform-provider-random rename to getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/random/1.2.0/linux_amd64/terraform-provider-random diff --git a/internal/getproviders/testdata/filesystem-mirror/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64/extra-data.txt b/getproviders/testdata/filesystem-mirror/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64/extra-data.txt similarity index 100% rename from internal/getproviders/testdata/filesystem-mirror/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64/extra-data.txt rename to getproviders/testdata/filesystem-mirror/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64/extra-data.txt diff --git a/internal/getproviders/testdata/filesystem-mirror/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64/terraform-provider-happycloud b/getproviders/testdata/filesystem-mirror/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64/terraform-provider-happycloud similarity index 100% rename from internal/getproviders/testdata/filesystem-mirror/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64/terraform-provider-happycloud rename to getproviders/testdata/filesystem-mirror/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64/terraform-provider-happycloud diff --git a/internal/getproviders/testdata/search-local-directory/symlinks/real/example.com/foo/bar/1.0.0/linux_amd64/terraform-provider-bar b/getproviders/testdata/search-local-directory/symlinks/real/example.com/foo/bar/1.0.0/linux_amd64/terraform-provider-bar similarity index 100% rename from internal/getproviders/testdata/search-local-directory/symlinks/real/example.com/foo/bar/1.0.0/linux_amd64/terraform-provider-bar rename to getproviders/testdata/search-local-directory/symlinks/real/example.com/foo/bar/1.0.0/linux_amd64/terraform-provider-bar diff --git a/internal/getproviders/testdata/search-local-directory/symlinks/real/example.net b/getproviders/testdata/search-local-directory/symlinks/real/example.net similarity index 100% rename from internal/getproviders/testdata/search-local-directory/symlinks/real/example.net rename to getproviders/testdata/search-local-directory/symlinks/real/example.net diff --git a/internal/getproviders/testdata/search-local-directory/symlinks/symlink b/getproviders/testdata/search-local-directory/symlinks/symlink similarity index 100% rename from internal/getproviders/testdata/search-local-directory/symlinks/symlink rename to getproviders/testdata/search-local-directory/symlinks/symlink diff --git a/internal/getproviders/types.go b/getproviders/types.go similarity index 99% rename from internal/getproviders/types.go rename to getproviders/types.go index 28b1913d67a2..951d6f0961fd 100644 --- a/internal/getproviders/types.go +++ b/getproviders/types.go @@ -9,7 +9,7 @@ import ( "github.com/apparentlymart/go-versions/versions" "github.com/apparentlymart/go-versions/versions/constraints" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) // Version represents a particular single version of a provider. diff --git a/internal/getproviders/types_test.go b/getproviders/types_test.go similarity index 100% rename from internal/getproviders/types_test.go rename to getproviders/types_test.go diff --git a/internal/grpcwrap/provider.go b/grpcwrap/provider.go similarity index 98% rename from internal/grpcwrap/provider.go rename to grpcwrap/provider.go index 170cea63881a..9b9719b179be 100644 --- a/internal/grpcwrap/provider.go +++ b/grpcwrap/provider.go @@ -3,9 +3,9 @@ package grpcwrap import ( "context" - "github.com/hashicorp/terraform/internal/plugin/convert" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/tfplugin5" + "github.com/hashicorp/terraform/plugin/convert" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/tfplugin5" "github.com/zclconf/go-cty/cty" ctyjson "github.com/zclconf/go-cty/cty/json" "github.com/zclconf/go-cty/cty/msgpack" diff --git a/internal/grpcwrap/provider6.go b/grpcwrap/provider6.go similarity index 98% rename from internal/grpcwrap/provider6.go rename to grpcwrap/provider6.go index af287d0f5444..4a44e688e42c 100644 --- a/internal/grpcwrap/provider6.go +++ b/grpcwrap/provider6.go @@ -3,9 +3,9 @@ package grpcwrap import ( "context" - "github.com/hashicorp/terraform/internal/plugin6/convert" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/tfplugin6" + "github.com/hashicorp/terraform/plugin6/convert" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/tfplugin6" "github.com/zclconf/go-cty/cty" ctyjson "github.com/zclconf/go-cty/cty/json" "github.com/zclconf/go-cty/cty/msgpack" diff --git a/internal/grpcwrap/provisioner.go b/grpcwrap/provisioner.go similarity index 91% rename from internal/grpcwrap/provisioner.go rename to grpcwrap/provisioner.go index ef265248a6e2..91f707e27c7f 100644 --- a/internal/grpcwrap/provisioner.go +++ b/grpcwrap/provisioner.go @@ -6,11 +6,11 @@ import ( "strings" "unicode/utf8" - "github.com/hashicorp/terraform/internal/communicator/shared" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/plugin/convert" - "github.com/hashicorp/terraform/internal/provisioners" - "github.com/hashicorp/terraform/internal/tfplugin5" + "github.com/hashicorp/terraform/communicator/shared" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/plugin/convert" + "github.com/hashicorp/terraform/provisioners" + "github.com/hashicorp/terraform/tfplugin5" ) // New wraps a provisioners.Interface to implement a grpc ProviderServer. diff --git a/internal/helper/slowmessage/slowmessage.go b/helper/slowmessage/slowmessage.go similarity index 100% rename from internal/helper/slowmessage/slowmessage.go rename to helper/slowmessage/slowmessage.go diff --git a/internal/helper/slowmessage/slowmessage_test.go b/helper/slowmessage/slowmessage_test.go similarity index 100% rename from internal/helper/slowmessage/slowmessage_test.go rename to helper/slowmessage/slowmessage_test.go diff --git a/internal/httpclient/client.go b/httpclient/client.go similarity index 100% rename from internal/httpclient/client.go rename to httpclient/client.go diff --git a/internal/httpclient/client_test.go b/httpclient/client_test.go similarity index 100% rename from internal/httpclient/client_test.go rename to httpclient/client_test.go diff --git a/internal/httpclient/useragent.go b/httpclient/useragent.go similarity index 100% rename from internal/httpclient/useragent.go rename to httpclient/useragent.go diff --git a/internal/httpclient/useragent_test.go b/httpclient/useragent_test.go similarity index 100% rename from internal/httpclient/useragent_test.go rename to httpclient/useragent_test.go diff --git a/internal/initwd/doc.go b/initwd/doc.go similarity index 100% rename from internal/initwd/doc.go rename to initwd/doc.go diff --git a/internal/initwd/from_module.go b/initwd/from_module.go similarity index 97% rename from internal/initwd/from_module.go rename to initwd/from_module.go index 38a4e49b5cee..3af3a627eb3e 100644 --- a/internal/initwd/from_module.go +++ b/initwd/from_module.go @@ -10,15 +10,15 @@ import ( "sort" "strings" - "github.com/hashicorp/terraform/internal/copy" - "github.com/hashicorp/terraform/internal/earlyconfig" - "github.com/hashicorp/terraform/internal/getmodules" + "github.com/hashicorp/terraform/copy" + "github.com/hashicorp/terraform/earlyconfig" + "github.com/hashicorp/terraform/getmodules" version "github.com/hashicorp/go-version" "github.com/hashicorp/terraform-config-inspect/tfconfig" - "github.com/hashicorp/terraform/internal/modsdir" - "github.com/hashicorp/terraform/internal/registry" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/modsdir" + "github.com/hashicorp/terraform/registry" + "github.com/hashicorp/terraform/tfdiags" ) const initFromModuleRootCallName = "root" diff --git a/internal/initwd/from_module_test.go b/initwd/from_module_test.go similarity index 97% rename from internal/initwd/from_module_test.go rename to initwd/from_module_test.go index 9714ed3465f7..dddfce312bcc 100644 --- a/internal/initwd/from_module_test.go +++ b/initwd/from_module_test.go @@ -9,11 +9,11 @@ import ( "github.com/google/go-cmp/cmp" version "github.com/hashicorp/go-version" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configload" - "github.com/hashicorp/terraform/internal/copy" - "github.com/hashicorp/terraform/internal/registry" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/copy" + "github.com/hashicorp/terraform/registry" + "github.com/hashicorp/terraform/tfdiags" ) func TestDirFromModule_registry(t *testing.T) { diff --git a/internal/initwd/load_config.go b/initwd/load_config.go similarity index 91% rename from internal/initwd/load_config.go rename to initwd/load_config.go index 6dc032ba1704..741d8189a89f 100644 --- a/internal/initwd/load_config.go +++ b/initwd/load_config.go @@ -5,9 +5,9 @@ import ( version "github.com/hashicorp/go-version" "github.com/hashicorp/terraform-config-inspect/tfconfig" - "github.com/hashicorp/terraform/internal/earlyconfig" - "github.com/hashicorp/terraform/internal/modsdir" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/earlyconfig" + "github.com/hashicorp/terraform/modsdir" + "github.com/hashicorp/terraform/tfdiags" ) // LoadConfig loads a full configuration tree that has previously had all of diff --git a/internal/initwd/module_install.go b/initwd/module_install.go similarity index 98% rename from internal/initwd/module_install.go rename to initwd/module_install.go index 2a1f7b685f3d..411df0e52766 100644 --- a/internal/initwd/module_install.go +++ b/initwd/module_install.go @@ -14,14 +14,14 @@ import ( version "github.com/hashicorp/go-version" "github.com/hashicorp/terraform-config-inspect/tfconfig" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/earlyconfig" - "github.com/hashicorp/terraform/internal/getmodules" - "github.com/hashicorp/terraform/internal/modsdir" - "github.com/hashicorp/terraform/internal/registry" - "github.com/hashicorp/terraform/internal/registry/regsrc" - "github.com/hashicorp/terraform/internal/registry/response" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/earlyconfig" + "github.com/hashicorp/terraform/getmodules" + "github.com/hashicorp/terraform/modsdir" + "github.com/hashicorp/terraform/registry" + "github.com/hashicorp/terraform/registry/regsrc" + "github.com/hashicorp/terraform/registry/response" + "github.com/hashicorp/terraform/tfdiags" ) type ModuleInstaller struct { diff --git a/internal/initwd/module_install_hooks.go b/initwd/module_install_hooks.go similarity index 100% rename from internal/initwd/module_install_hooks.go rename to initwd/module_install_hooks.go diff --git a/internal/initwd/module_install_test.go b/initwd/module_install_test.go similarity index 98% rename from internal/initwd/module_install_test.go rename to initwd/module_install_test.go index 6f77c60f60ea..f26b8eb03476 100644 --- a/internal/initwd/module_install_test.go +++ b/initwd/module_install_test.go @@ -16,14 +16,14 @@ import ( "github.com/google/go-cmp/cmp" version "github.com/hashicorp/go-version" svchost "github.com/hashicorp/terraform-svchost" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configload" - "github.com/hashicorp/terraform/internal/copy" - "github.com/hashicorp/terraform/internal/registry" - "github.com/hashicorp/terraform/internal/tfdiags" - - _ "github.com/hashicorp/terraform/internal/logging" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/copy" + "github.com/hashicorp/terraform/registry" + "github.com/hashicorp/terraform/tfdiags" + + _ "github.com/hashicorp/terraform/logging" ) func TestMain(m *testing.M) { diff --git a/internal/initwd/testdata/already-installed/root.tf b/initwd/testdata/already-installed/root.tf similarity index 100% rename from internal/initwd/testdata/already-installed/root.tf rename to initwd/testdata/already-installed/root.tf diff --git a/internal/initwd/testdata/empty/.gitignore b/initwd/testdata/empty/.gitignore similarity index 100% rename from internal/initwd/testdata/empty/.gitignore rename to initwd/testdata/empty/.gitignore diff --git a/internal/initwd/testdata/go-getter-modules/.gitignore b/initwd/testdata/go-getter-modules/.gitignore similarity index 100% rename from internal/initwd/testdata/go-getter-modules/.gitignore rename to initwd/testdata/go-getter-modules/.gitignore diff --git a/internal/initwd/testdata/go-getter-modules/root.tf b/initwd/testdata/go-getter-modules/root.tf similarity index 100% rename from internal/initwd/testdata/go-getter-modules/root.tf rename to initwd/testdata/go-getter-modules/root.tf diff --git a/internal/initwd/testdata/invalid-version-constraint-local/.gitignore b/initwd/testdata/invalid-version-constraint-local/.gitignore similarity index 100% rename from internal/initwd/testdata/invalid-version-constraint-local/.gitignore rename to initwd/testdata/invalid-version-constraint-local/.gitignore diff --git a/internal/initwd/testdata/invalid-version-constraint-local/root.tf b/initwd/testdata/invalid-version-constraint-local/root.tf similarity index 100% rename from internal/initwd/testdata/invalid-version-constraint-local/root.tf rename to initwd/testdata/invalid-version-constraint-local/root.tf diff --git a/internal/initwd/testdata/invalid-version-constraint/.gitignore b/initwd/testdata/invalid-version-constraint/.gitignore similarity index 100% rename from internal/initwd/testdata/invalid-version-constraint/.gitignore rename to initwd/testdata/invalid-version-constraint/.gitignore diff --git a/internal/initwd/testdata/invalid-version-constraint/root.tf b/initwd/testdata/invalid-version-constraint/root.tf similarity index 100% rename from internal/initwd/testdata/invalid-version-constraint/root.tf rename to initwd/testdata/invalid-version-constraint/root.tf diff --git a/internal/initwd/testdata/load-module-package-escape/child/package-escape-child.tf b/initwd/testdata/load-module-package-escape/child/package-escape-child.tf similarity index 100% rename from internal/initwd/testdata/load-module-package-escape/child/package-escape-child.tf rename to initwd/testdata/load-module-package-escape/child/package-escape-child.tf diff --git a/internal/initwd/testdata/load-module-package-escape/grandchild/package-escape-grandchild.tf b/initwd/testdata/load-module-package-escape/grandchild/package-escape-grandchild.tf similarity index 100% rename from internal/initwd/testdata/load-module-package-escape/grandchild/package-escape-grandchild.tf rename to initwd/testdata/load-module-package-escape/grandchild/package-escape-grandchild.tf diff --git a/internal/initwd/testdata/load-module-package-escape/package-escape.tf b/initwd/testdata/load-module-package-escape/package-escape.tf similarity index 100% rename from internal/initwd/testdata/load-module-package-escape/package-escape.tf rename to initwd/testdata/load-module-package-escape/package-escape.tf diff --git a/internal/initwd/testdata/load-module-package-prefix/package-prefix.tf b/initwd/testdata/load-module-package-prefix/package-prefix.tf similarity index 100% rename from internal/initwd/testdata/load-module-package-prefix/package-prefix.tf rename to initwd/testdata/load-module-package-prefix/package-prefix.tf diff --git a/internal/initwd/testdata/load-module-package-prefix/package/child/package-prefix-child.tf b/initwd/testdata/load-module-package-prefix/package/child/package-prefix-child.tf similarity index 100% rename from internal/initwd/testdata/load-module-package-prefix/package/child/package-prefix-child.tf rename to initwd/testdata/load-module-package-prefix/package/child/package-prefix-child.tf diff --git a/internal/initwd/testdata/load-module-package-prefix/package/grandchild/package-prefix-grandchild.tf b/initwd/testdata/load-module-package-prefix/package/grandchild/package-prefix-grandchild.tf similarity index 100% rename from internal/initwd/testdata/load-module-package-prefix/package/grandchild/package-prefix-grandchild.tf rename to initwd/testdata/load-module-package-prefix/package/grandchild/package-prefix-grandchild.tf diff --git a/internal/initwd/testdata/local-module-error/child_a/main.tf b/initwd/testdata/local-module-error/child_a/main.tf similarity index 100% rename from internal/initwd/testdata/local-module-error/child_a/main.tf rename to initwd/testdata/local-module-error/child_a/main.tf diff --git a/internal/initwd/testdata/local-module-error/main.tf b/initwd/testdata/local-module-error/main.tf similarity index 100% rename from internal/initwd/testdata/local-module-error/main.tf rename to initwd/testdata/local-module-error/main.tf diff --git a/internal/initwd/testdata/local-module-symlink/child_a/child_a.tf b/initwd/testdata/local-module-symlink/child_a/child_a.tf similarity index 100% rename from internal/initwd/testdata/local-module-symlink/child_a/child_a.tf rename to initwd/testdata/local-module-symlink/child_a/child_a.tf diff --git a/internal/initwd/testdata/local-module-symlink/child_a/child_b/child_b.tf b/initwd/testdata/local-module-symlink/child_a/child_b/child_b.tf similarity index 100% rename from internal/initwd/testdata/local-module-symlink/child_a/child_b/child_b.tf rename to initwd/testdata/local-module-symlink/child_a/child_b/child_b.tf diff --git a/internal/initwd/testdata/local-module-symlink/modules/child_a b/initwd/testdata/local-module-symlink/modules/child_a similarity index 100% rename from internal/initwd/testdata/local-module-symlink/modules/child_a rename to initwd/testdata/local-module-symlink/modules/child_a diff --git a/internal/initwd/testdata/local-module-symlink/root.tf b/initwd/testdata/local-module-symlink/root.tf similarity index 100% rename from internal/initwd/testdata/local-module-symlink/root.tf rename to initwd/testdata/local-module-symlink/root.tf diff --git a/internal/initwd/testdata/local-modules/child_a/child_a.tf b/initwd/testdata/local-modules/child_a/child_a.tf similarity index 100% rename from internal/initwd/testdata/local-modules/child_a/child_a.tf rename to initwd/testdata/local-modules/child_a/child_a.tf diff --git a/internal/initwd/testdata/local-modules/child_a/child_b/child_b.tf b/initwd/testdata/local-modules/child_a/child_b/child_b.tf similarity index 100% rename from internal/initwd/testdata/local-modules/child_a/child_b/child_b.tf rename to initwd/testdata/local-modules/child_a/child_b/child_b.tf diff --git a/internal/initwd/testdata/local-modules/root.tf b/initwd/testdata/local-modules/root.tf similarity index 100% rename from internal/initwd/testdata/local-modules/root.tf rename to initwd/testdata/local-modules/root.tf diff --git a/internal/initwd/testdata/prerelease-version-constraint-match/root.tf b/initwd/testdata/prerelease-version-constraint-match/root.tf similarity index 100% rename from internal/initwd/testdata/prerelease-version-constraint-match/root.tf rename to initwd/testdata/prerelease-version-constraint-match/root.tf diff --git a/internal/initwd/testdata/prerelease-version-constraint/root.tf b/initwd/testdata/prerelease-version-constraint/root.tf similarity index 100% rename from internal/initwd/testdata/prerelease-version-constraint/root.tf rename to initwd/testdata/prerelease-version-constraint/root.tf diff --git a/internal/initwd/testdata/registry-modules/.gitignore b/initwd/testdata/registry-modules/.gitignore similarity index 100% rename from internal/initwd/testdata/registry-modules/.gitignore rename to initwd/testdata/registry-modules/.gitignore diff --git a/internal/initwd/testdata/registry-modules/root.tf b/initwd/testdata/registry-modules/root.tf similarity index 100% rename from internal/initwd/testdata/registry-modules/root.tf rename to initwd/testdata/registry-modules/root.tf diff --git a/internal/initwd/testing.go b/initwd/testing.go similarity index 92% rename from internal/initwd/testing.go rename to initwd/testing.go index 406718159c43..5fe6c768f0fb 100644 --- a/internal/initwd/testing.go +++ b/initwd/testing.go @@ -4,10 +4,10 @@ import ( "context" "testing" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configload" - "github.com/hashicorp/terraform/internal/registry" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/registry" + "github.com/hashicorp/terraform/tfdiags" ) // LoadConfigForTests is a convenience wrapper around configload.NewLoaderForTests, diff --git a/internal/instances/expander.go b/instances/expander.go similarity index 99% rename from internal/instances/expander.go rename to instances/expander.go index 2c912c897dc8..45b50221fdbc 100644 --- a/internal/instances/expander.go +++ b/instances/expander.go @@ -5,7 +5,7 @@ import ( "sort" "sync" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/instances/expander_test.go b/instances/expander_test.go similarity index 99% rename from internal/instances/expander_test.go rename to instances/expander_test.go index 2e983288929a..a82cf50baaa3 100644 --- a/internal/instances/expander_test.go +++ b/instances/expander_test.go @@ -8,7 +8,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) func TestExpander(t *testing.T) { diff --git a/internal/instances/expansion_mode.go b/instances/expansion_mode.go similarity index 97% rename from internal/instances/expansion_mode.go rename to instances/expansion_mode.go index 1183e3c768cf..be33934324e8 100644 --- a/internal/instances/expansion_mode.go +++ b/instances/expansion_mode.go @@ -6,7 +6,7 @@ import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) // expansion is an internal interface used to represent the different diff --git a/internal/instances/instance_key_data.go b/instances/instance_key_data.go similarity index 100% rename from internal/instances/instance_key_data.go rename to instances/instance_key_data.go diff --git a/internal/instances/set.go b/instances/set.go similarity index 97% rename from internal/instances/set.go rename to instances/set.go index 701a2d27e042..714e68ef8ee1 100644 --- a/internal/instances/set.go +++ b/instances/set.go @@ -1,7 +1,7 @@ package instances import ( - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) // Set is a set of instances, intended mainly for the return value of diff --git a/internal/instances/set_test.go b/instances/set_test.go similarity index 99% rename from internal/instances/set_test.go rename to instances/set_test.go index e255cef1b888..fcb381dcd6db 100644 --- a/internal/instances/set_test.go +++ b/instances/set_test.go @@ -3,7 +3,7 @@ package instances import ( "testing" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64/terraform-provider-null.exe b/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64/terraform-provider-null.exe deleted file mode 100644 index daa9e3509f65..000000000000 --- a/internal/getproviders/testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64/terraform-provider-null.exe +++ /dev/null @@ -1 +0,0 @@ -# This is just a placeholder file for discovery testing, not a real provider plugin. diff --git a/internal/plugin/discovery/testdata/current-style-plugins/mockos_mockarch/terraform-foo-bar_v1.0.0.exe b/internal/plugin/discovery/testdata/current-style-plugins/mockos_mockarch/terraform-foo-bar_v1.0.0.exe deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/internal/plugin/mock_proto/generate.go b/internal/plugin/mock_proto/generate.go deleted file mode 100644 index 6f004ffd362a..000000000000 --- a/internal/plugin/mock_proto/generate.go +++ /dev/null @@ -1,3 +0,0 @@ -//go:generate go run github.com/golang/mock/mockgen -destination mock.go github.com/hashicorp/terraform/internal/tfplugin5 ProviderClient,ProvisionerClient,Provisioner_ProvisionResourceClient,Provisioner_ProvisionResourceServer - -package mock_tfplugin5 diff --git a/internal/provider-simple-v6/main/main.go b/internal/provider-simple-v6/main/main.go deleted file mode 100644 index cc2bbc3c3fab..000000000000 --- a/internal/provider-simple-v6/main/main.go +++ /dev/null @@ -1,16 +0,0 @@ -package main - -import ( - "github.com/hashicorp/terraform/internal/grpcwrap" - plugin "github.com/hashicorp/terraform/internal/plugin6" - simple "github.com/hashicorp/terraform/internal/provider-simple-v6" - "github.com/hashicorp/terraform/internal/tfplugin6" -) - -func main() { - plugin.Serve(&plugin.ServeOpts{ - GRPCProviderFunc: func() tfplugin6.ProviderServer { - return grpcwrap.Provider6(simple.Provider()) - }, - }) -} diff --git a/internal/provider-simple/main/main.go b/internal/provider-simple/main/main.go deleted file mode 100644 index 8e8ceadff933..000000000000 --- a/internal/provider-simple/main/main.go +++ /dev/null @@ -1,16 +0,0 @@ -package main - -import ( - "github.com/hashicorp/terraform/internal/grpcwrap" - "github.com/hashicorp/terraform/internal/plugin" - simple "github.com/hashicorp/terraform/internal/provider-simple" - "github.com/hashicorp/terraform/internal/tfplugin5" -) - -func main() { - plugin.Serve(&plugin.ServeOpts{ - GRPCProviderFunc: func() tfplugin5.ProviderServer { - return grpcwrap.Provider(simple.Provider()) - }, - }) -} diff --git a/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64/terraform-provider-null.exe b/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64/terraform-provider-null.exe deleted file mode 100644 index daa9e3509f65..000000000000 --- a/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64/terraform-provider-null.exe +++ /dev/null @@ -1 +0,0 @@ -# This is just a placeholder file for discovery testing, not a real provider plugin. diff --git a/internal/terraform/context.go b/internal/terraform/context.go deleted file mode 100644 index 18b3f4b37b54..000000000000 --- a/internal/terraform/context.go +++ /dev/null @@ -1,431 +0,0 @@ -package terraform - -import ( - "context" - "fmt" - "log" - "sort" - "sync" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/logging" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/provisioners" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" - "github.com/zclconf/go-cty/cty" -) - -// InputMode defines what sort of input will be asked for when Input -// is called on Context. -type InputMode byte - -const ( - // InputModeProvider asks for provider variables - InputModeProvider InputMode = 1 << iota - - // InputModeStd is the standard operating mode and asks for both variables - // and providers. - InputModeStd = InputModeProvider -) - -// ContextOpts are the user-configurable options to create a context with -// NewContext. -type ContextOpts struct { - Meta *ContextMeta - Hooks []Hook - Parallelism int - Providers map[addrs.Provider]providers.Factory - Provisioners map[string]provisioners.Factory - - UIInput UIInput -} - -// ContextMeta is metadata about the running context. This is information -// that this package or structure cannot determine on its own but exposes -// into Terraform in various ways. This must be provided by the Context -// initializer. -type ContextMeta struct { - Env string // Env is the state environment - - // OriginalWorkingDir is the working directory where the Terraform CLI - // was run from, which may no longer actually be the current working - // directory if the user included the -chdir=... option. - // - // If this string is empty then the original working directory is the same - // as the current working directory. - // - // In most cases we should respect the user's override by ignoring this - // path and just using the current working directory, but this is here - // for some exceptional cases where the original working directory is - // needed. - OriginalWorkingDir string -} - -// Context represents all the context that Terraform needs in order to -// perform operations on infrastructure. This structure is built using -// NewContext. -type Context struct { - // meta captures some misc. information about the working directory where - // we're taking these actions, and thus which should remain steady between - // operations. - meta *ContextMeta - - plugins *contextPlugins - - hooks []Hook - sh *stopHook - uiInput UIInput - - l sync.Mutex // Lock acquired during any task - parallelSem Semaphore - providerInputConfig map[string]map[string]cty.Value - runCond *sync.Cond - runContext context.Context - runContextCancel context.CancelFunc -} - -// (additional methods on Context can be found in context_*.go files.) - -// NewContext creates a new Context structure. -// -// Once a Context is created, the caller must not access or mutate any of -// the objects referenced (directly or indirectly) by the ContextOpts fields. -// -// If the returned diagnostics contains errors then the resulting context is -// invalid and must not be used. -func NewContext(opts *ContextOpts) (*Context, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - - log.Printf("[TRACE] terraform.NewContext: starting") - - // Copy all the hooks and add our stop hook. We don't append directly - // to the Config so that we're not modifying that in-place. - sh := new(stopHook) - hooks := make([]Hook, len(opts.Hooks)+1) - copy(hooks, opts.Hooks) - hooks[len(opts.Hooks)] = sh - - // Determine parallelism, default to 10. We do this both to limit - // CPU pressure but also to have an extra guard against rate throttling - // from providers. - // We throw an error in case of negative parallelism - par := opts.Parallelism - if par < 0 { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Invalid parallelism value", - fmt.Sprintf("The parallelism must be a positive value. Not %d.", par), - )) - return nil, diags - } - - if par == 0 { - par = 10 - } - - plugins := newContextPlugins(opts.Providers, opts.Provisioners) - - log.Printf("[TRACE] terraform.NewContext: complete") - - return &Context{ - hooks: hooks, - meta: opts.Meta, - uiInput: opts.UIInput, - - plugins: plugins, - - parallelSem: NewSemaphore(par), - providerInputConfig: make(map[string]map[string]cty.Value), - sh: sh, - }, diags -} - -func (c *Context) Schemas(config *configs.Config, state *states.State) (*Schemas, tfdiags.Diagnostics) { - // TODO: This method gets called multiple times on the same context with - // the same inputs by different parts of Terraform that all need the - // schemas, and it's typically quite expensive because it has to spin up - // plugins to gather their schemas, so it'd be good to have some caching - // here to remember plugin schemas we already loaded since the plugin - // selections can't change during the life of a *Context object. - - var diags tfdiags.Diagnostics - - ret, err := loadSchemas(config, state, c.plugins) - if err != nil { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Failed to load plugin schemas", - fmt.Sprintf("Error while loading schemas for plugin components: %s.", err), - )) - return nil, diags - } - return ret, diags -} - -type ContextGraphOpts struct { - // If true, validates the graph structure (checks for cycles). - Validate bool - - // Legacy graphs only: won't prune the graph - Verbose bool -} - -// Stop stops the running task. -// -// Stop will block until the task completes. -func (c *Context) Stop() { - log.Printf("[WARN] terraform: Stop called, initiating interrupt sequence") - - c.l.Lock() - defer c.l.Unlock() - - // If we're running, then stop - if c.runContextCancel != nil { - log.Printf("[WARN] terraform: run context exists, stopping") - - // Tell the hook we want to stop - c.sh.Stop() - - // Stop the context - c.runContextCancel() - c.runContextCancel = nil - } - - // Grab the condition var before we exit - if cond := c.runCond; cond != nil { - log.Printf("[INFO] terraform: waiting for graceful stop to complete") - cond.Wait() - } - - log.Printf("[WARN] terraform: stop complete") -} - -func (c *Context) acquireRun(phase string) func() { - // With the run lock held, grab the context lock to make changes - // to the run context. - c.l.Lock() - defer c.l.Unlock() - - // Wait until we're no longer running - for c.runCond != nil { - c.runCond.Wait() - } - - // Build our lock - c.runCond = sync.NewCond(&c.l) - - // Create a new run context - c.runContext, c.runContextCancel = context.WithCancel(context.Background()) - - // Reset the stop hook so we're not stopped - c.sh.Reset() - - return c.releaseRun -} - -func (c *Context) releaseRun() { - // Grab the context lock so that we can make modifications to fields - c.l.Lock() - defer c.l.Unlock() - - // End our run. We check if runContext is non-nil because it can be - // set to nil if it was cancelled via Stop() - if c.runContextCancel != nil { - c.runContextCancel() - } - - // Unlock all waiting our condition - cond := c.runCond - c.runCond = nil - cond.Broadcast() - - // Unset the context - c.runContext = nil -} - -// watchStop immediately returns a `stop` and a `wait` chan after dispatching -// the watchStop goroutine. This will watch the runContext for cancellation and -// stop the providers accordingly. When the watch is no longer needed, the -// `stop` chan should be closed before waiting on the `wait` chan. -// The `wait` chan is important, because without synchronizing with the end of -// the watchStop goroutine, the runContext may also be closed during the select -// incorrectly causing providers to be stopped. Even if the graph walk is done -// at that point, stopping a provider permanently cancels its StopContext which -// can cause later actions to fail. -func (c *Context) watchStop(walker *ContextGraphWalker) (chan struct{}, <-chan struct{}) { - stop := make(chan struct{}) - wait := make(chan struct{}) - - // get the runContext cancellation channel now, because releaseRun will - // write to the runContext field. - done := c.runContext.Done() - - go func() { - defer logging.PanicHandler() - - defer close(wait) - // Wait for a stop or completion - select { - case <-done: - // done means the context was canceled, so we need to try and stop - // providers. - case <-stop: - // our own stop channel was closed. - return - } - - // If we're here, we're stopped, trigger the call. - log.Printf("[TRACE] Context: requesting providers and provisioners to gracefully stop") - - { - // Copy the providers so that a misbehaved blocking Stop doesn't - // completely hang Terraform. - walker.providerLock.Lock() - ps := make([]providers.Interface, 0, len(walker.providerCache)) - for _, p := range walker.providerCache { - ps = append(ps, p) - } - defer walker.providerLock.Unlock() - - for _, p := range ps { - // We ignore the error for now since there isn't any reasonable - // action to take if there is an error here, since the stop is still - // advisory: Terraform will exit once the graph node completes. - p.Stop() - } - } - - { - // Call stop on all the provisioners - walker.provisionerLock.Lock() - ps := make([]provisioners.Interface, 0, len(walker.provisionerCache)) - for _, p := range walker.provisionerCache { - ps = append(ps, p) - } - defer walker.provisionerLock.Unlock() - - for _, p := range ps { - // We ignore the error for now since there isn't any reasonable - // action to take if there is an error here, since the stop is still - // advisory: Terraform will exit once the graph node completes. - p.Stop() - } - } - }() - - return stop, wait -} - -// checkConfigDependencies checks whether the recieving context is able to -// support the given configuration, returning error diagnostics if not. -// -// Currently this function checks whether the current Terraform CLI version -// matches the version requirements of all of the modules, and whether our -// plugin library contains all of the plugin names/addresses needed. -// -// This function does *not* check that external modules are installed (that's -// the responsibility of the configuration loader) and doesn't check that the -// plugins are of suitable versions to match any version constraints (which is -// the responsibility of the code which installed the plugins and then -// constructed the Providers/Provisioners maps passed in to NewContext). -// -// In most cases we should typically catch the problems this function detects -// before we reach this point, but this function can come into play in some -// unusual cases outside of the main workflow, and can avoid some -// potentially-more-confusing errors from later operations. -func (c *Context) checkConfigDependencies(config *configs.Config) tfdiags.Diagnostics { - var diags tfdiags.Diagnostics - - // This checks the Terraform CLI version constraints specified in all of - // the modules. - diags = diags.Append(CheckCoreVersionRequirements(config)) - - // We only check that we have a factory for each required provider, and - // assume the caller already assured that any separately-installed - // plugins are of a suitable version, match expected checksums, etc. - providerReqs, hclDiags := config.ProviderRequirements() - diags = diags.Append(hclDiags) - if hclDiags.HasErrors() { - return diags - } - for providerAddr := range providerReqs { - if !c.plugins.HasProvider(providerAddr) { - if !providerAddr.IsBuiltIn() { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Missing required provider", - fmt.Sprintf( - "This configuration requires provider %s, but that provider isn't available. You may be able to install it automatically by running:\n terraform init", - providerAddr, - ), - )) - } else { - // Built-in providers can never be installed by "terraform init", - // so no point in confusing the user by suggesting that. - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Missing required provider", - fmt.Sprintf( - "This configuration requires built-in provider %s, but that provider isn't available in this Terraform version.", - providerAddr, - ), - )) - } - } - } - - // Our handling of provisioners is much less sophisticated than providers - // because they are in many ways a legacy system. We need to go hunting - // for them more directly in the configuration. - config.DeepEach(func(modCfg *configs.Config) { - if modCfg == nil || modCfg.Module == nil { - return // should not happen, but we'll be robust - } - for _, rc := range modCfg.Module.ManagedResources { - if rc.Managed == nil { - continue // should not happen, but we'll be robust - } - for _, pc := range rc.Managed.Provisioners { - if !c.plugins.HasProvisioner(pc.Type) { - // This is not a very high-quality error, because really - // the caller of terraform.NewContext should've already - // done equivalent checks when doing plugin discovery. - // This is just to make sure we return a predictable - // error in a central place, rather than failing somewhere - // later in the non-deterministically-ordered graph walk. - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Missing required provisioner plugin", - fmt.Sprintf( - "This configuration requires provisioner plugin %q, which isn't available. If you're intending to use an external provisioner plugin, you must install it manually into one of the plugin search directories before running Terraform.", - pc.Type, - ), - )) - } - } - } - }) - - // Because we were doing a lot of map iteration above, and we're only - // generating sourceless diagnostics anyway, our diagnostics will not be - // in a deterministic order. To ensure stable output when there are - // multiple errors to report, we'll sort these particular diagnostics - // so they are at least always consistent alone. This ordering is - // arbitrary and not a compatibility constraint. - sort.Slice(diags, func(i, j int) bool { - // Because these are sourcelss diagnostics and we know they are all - // errors, we know they'll only differ in their description fields. - descI := diags[i].Description() - descJ := diags[j].Description() - switch { - case descI.Summary != descJ.Summary: - return descI.Summary < descJ.Summary - default: - return descI.Detail < descJ.Detail - } - }) - - return diags -} diff --git a/internal/terraform/context_apply.go b/internal/terraform/context_apply.go deleted file mode 100644 index ada934e3f5c6..000000000000 --- a/internal/terraform/context_apply.go +++ /dev/null @@ -1,187 +0,0 @@ -package terraform - -import ( - "fmt" - "log" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" - "github.com/zclconf/go-cty/cty" -) - -// Apply performs the actions described by the given Plan object and returns -// the resulting updated state. -// -// The given configuration *must* be the same configuration that was passed -// earlier to Context.Plan in order to create this plan. -// -// Even if the returned diagnostics contains errors, Apply always returns the -// resulting state which is likely to have been partially-updated. -func (c *Context) Apply(plan *plans.Plan, config *configs.Config) (*states.State, tfdiags.Diagnostics) { - defer c.acquireRun("apply")() - - log.Printf("[DEBUG] Building and walking apply graph for %s plan", plan.UIMode) - - if plan.Errored { - var diags tfdiags.Diagnostics - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Cannot apply failed plan", - `The given plan is incomplete due to errors during planning, and so it cannot be applied.`, - )) - return nil, diags - } - - graph, operation, diags := c.applyGraph(plan, config, true) - if diags.HasErrors() { - return nil, diags - } - - workingState := plan.PriorState.DeepCopy() - walker, walkDiags := c.walk(graph, operation, &graphWalkOpts{ - Config: config, - InputState: workingState, - Changes: plan.Changes, - - // We need to propagate the check results from the plan phase, - // because that will tell us which checkable objects we're expecting - // to see updated results from during the apply step. - PlanTimeCheckResults: plan.Checks, - }) - diags = diags.Append(walker.NonFatalDiagnostics) - diags = diags.Append(walkDiags) - - // After the walk is finished, we capture a simplified snapshot of the - // check result data as part of the new state. - walker.State.RecordCheckResults(walker.Checks) - - newState := walker.State.Close() - if plan.UIMode == plans.DestroyMode && !diags.HasErrors() { - // NOTE: This is a vestigial violation of the rule that we mustn't - // use plan.UIMode to affect apply-time behavior. - // We ideally ought to just call newState.PruneResourceHusks - // unconditionally here, but we historically didn't and haven't yet - // verified that it'd be safe to do so. - newState.PruneResourceHusks() - } - - if len(plan.TargetAddrs) > 0 { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Warning, - "Applied changes may be incomplete", - `The plan was created with the -target option in effect, so some changes requested in the configuration may have been ignored and the output values may not be fully updated. Run the following command to verify that no other changes are pending: - terraform plan - -Note that the -target option is not suitable for routine use, and is provided only for exceptional situations such as recovering from errors or mistakes, or when Terraform specifically suggests to use it as part of an error message.`, - )) - } - - // FIXME: we cannot check for an empty plan for refresh-only, because root - // outputs are always stored as changes. The final condition of the state - // also depends on some cleanup which happens during the apply walk. It - // would probably make more sense if applying a refresh-only plan were - // simply just returning the planned state and checks, but some extra - // cleanup is going to be needed to make the plan state match what apply - // would do. For now we can copy the checks over which were overwritten - // during the apply walk. - // Despite the intent of UIMode, it must still be used for apply-time - // differences in destroy plans too, so we can make use of that here as - // well. - if plan.UIMode == plans.RefreshOnlyMode { - newState.CheckResults = plan.Checks.DeepCopy() - } - - return newState, diags -} - -func (c *Context) applyGraph(plan *plans.Plan, config *configs.Config, validate bool) (*Graph, walkOperation, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - - variables := InputValues{} - for name, dyVal := range plan.VariableValues { - val, err := dyVal.Decode(cty.DynamicPseudoType) - if err != nil { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Invalid variable value in plan", - fmt.Sprintf("Invalid value for variable %q recorded in plan file: %s.", name, err), - )) - continue - } - - variables[name] = &InputValue{ - Value: val, - SourceType: ValueFromPlan, - } - } - if diags.HasErrors() { - return nil, walkApply, diags - } - - // The plan.VariableValues field only records variables that were actually - // set by the caller in the PlanOpts, so we may need to provide - // placeholders for any other variables that the user didn't set, in - // which case Terraform will once again use the default value from the - // configuration when we visit these variables during the graph walk. - for name := range config.Module.Variables { - if _, ok := variables[name]; ok { - continue - } - variables[name] = &InputValue{ - Value: cty.NilVal, - SourceType: ValueFromPlan, - } - } - - operation := walkApply - if plan.UIMode == plans.DestroyMode { - // FIXME: Due to differences in how objects must be handled in the - // graph and evaluated during a complete destroy, we must continue to - // use plans.DestroyMode to switch on this behavior. If all objects - // which require special destroy handling can be tracked in the plan, - // then this switch will no longer be needed and we can remove the - // walkDestroy operation mode. - // TODO: Audit that and remove walkDestroy as an operation mode. - operation = walkDestroy - } - - graph, moreDiags := (&ApplyGraphBuilder{ - Config: config, - Changes: plan.Changes, - State: plan.PriorState, - RootVariableValues: variables, - Plugins: c.plugins, - Targets: plan.TargetAddrs, - ForceReplace: plan.ForceReplaceAddrs, - Operation: operation, - }).Build(addrs.RootModuleInstance) - diags = diags.Append(moreDiags) - if moreDiags.HasErrors() { - return nil, walkApply, diags - } - - return graph, operation, diags -} - -// ApplyGraphForUI is a last vestage of graphs in the public interface of -// Context (as opposed to graphs as an implementation detail) intended only for -// use by the "terraform graph" command when asked to render an apply-time -// graph. -// -// The result of this is intended only for rendering ot the user as a dot -// graph, and so may change in future in order to make the result more useful -// in that context, even if drifts away from the physical graph that Terraform -// Core currently uses as an implementation detail of planning. -func (c *Context) ApplyGraphForUI(plan *plans.Plan, config *configs.Config) (*Graph, tfdiags.Diagnostics) { - // For now though, this really is just the internal graph, confusing - // implementation details and all. - - var diags tfdiags.Diagnostics - - graph, _, moreDiags := c.applyGraph(plan, config, false) - diags = diags.Append(moreDiags) - return graph, diags -} diff --git a/internal/terraform/context_apply2_test.go b/internal/terraform/context_apply2_test.go deleted file mode 100644 index 97769176dd3b..000000000000 --- a/internal/terraform/context_apply2_test.go +++ /dev/null @@ -1,1956 +0,0 @@ -package terraform - -import ( - "bytes" - "errors" - "fmt" - "strings" - "sync" - "testing" - "time" - - "github.com/davecgh/go-spew/spew" - "github.com/google/go-cmp/cmp" - "github.com/zclconf/go-cty/cty" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/checks" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/lang/marks" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -// Test that the PreApply hook is called with the correct deposed key -func TestContext2Apply_createBeforeDestroy_deposedKeyPreApply(t *testing.T) { - m := testModule(t, "apply-cbd-deposed-only") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - - deposedKey := states.NewDeposedKey() - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceDeposed( - mustResourceInstanceAddr("aws_instance.bar").Resource, - deposedKey, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectTainted, - AttrsJSON: []byte(`{"id":"foo"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - hook := new(MockHook) - ctx := testContext2(t, &ContextOpts{ - Hooks: []Hook{hook}, - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } else { - t.Logf(legacyDiffComparisonString(plan.Changes)) - } - - _, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - // Verify PreApply was called correctly - if !hook.PreApplyCalled { - t.Fatalf("PreApply hook not called") - } - if addr, wantAddr := hook.PreApplyAddr, mustResourceInstanceAddr("aws_instance.bar"); !addr.Equal(wantAddr) { - t.Errorf("expected addr to be %s, but was %s", wantAddr, addr) - } - if gen := hook.PreApplyGen; gen != deposedKey { - t.Errorf("expected gen to be %q, but was %q", deposedKey, gen) - } -} - -func TestContext2Apply_destroyWithDataSourceExpansion(t *testing.T) { - // While managed resources store their destroy-time dependencies, data - // sources do not. This means that if a provider were only included in a - // destroy graph because of data sources, it could have dependencies which - // are not correctly ordered. Here we verify that the provider is not - // included in the destroy operation, and all dependency evaluations - // succeed. - - m := testModuleInline(t, map[string]string{ - "main.tf": ` -module "mod" { - source = "./mod" -} - -provider "other" { - foo = module.mod.data -} - -# this should not require the provider be present during destroy -data "other_data_source" "a" { -} -`, - - "mod/main.tf": ` -data "test_data_source" "a" { - count = 1 -} - -data "test_data_source" "b" { - count = data.test_data_source.a[0].foo == "ok" ? 1 : 0 -} - -output "data" { - value = data.test_data_source.a[0].foo == "ok" ? data.test_data_source.b[0].foo : "nope" -} -`, - }) - - testP := testProvider("test") - otherP := testProvider("other") - - readData := func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse { - return providers.ReadDataSourceResponse{ - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("data_source"), - "foo": cty.StringVal("ok"), - }), - } - } - - testP.ReadDataSourceFn = readData - otherP.ReadDataSourceFn = readData - - ps := map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(testP), - addrs.NewDefaultProvider("other"): testProviderFuncFixed(otherP), - } - - otherP.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) { - foo := req.Config.GetAttr("foo") - if foo.IsNull() || foo.AsString() != "ok" { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("incorrect config val: %#v\n", foo)) - } - return resp - } - - ctx := testContext2(t, &ContextOpts{ - Providers: ps, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatal(diags.Err()) - } - - _, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatal(diags.Err()) - } - - // now destroy the whole thing - ctx = testContext2(t, &ContextOpts{ - Providers: ps, - }) - - plan, diags = ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.DestroyMode, - }) - if diags.HasErrors() { - t.Fatal(diags.Err()) - } - - otherP.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) { - // should not be used to destroy data sources - resp.Diagnostics = resp.Diagnostics.Append(errors.New("provider should not be used")) - return resp - } - - _, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatal(diags.Err()) - } -} - -func TestContext2Apply_destroyThenUpdate(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "test_instance" "a" { - value = "udpated" -} -`, - }) - - p := testProvider("test") - p.PlanResourceChangeFn = testDiffFn - - var orderMu sync.Mutex - var order []string - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - id := req.PriorState.GetAttr("id").AsString() - if id == "b" { - // slow down the b destroy, since a should wait for it - time.Sleep(100 * time.Millisecond) - } - - orderMu.Lock() - order = append(order, id) - orderMu.Unlock() - - resp.NewState = req.PlannedState - return resp - } - - addrA := mustResourceInstanceAddr(`test_instance.a`) - addrB := mustResourceInstanceAddr(`test_instance.b`) - - state := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent(addrA, &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{"id":"a","value":"old","type":"test"}`), - Status: states.ObjectReady, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`)) - - // test_instance.b depended on test_instance.a, and therefor should be - // destroyed before any changes to test_instance.a - s.SetResourceInstanceCurrent(addrB, &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{"id":"b"}`), - Status: states.ObjectReady, - Dependencies: []addrs.ConfigResource{addrA.ContainingResource().Config()}, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`)) - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - _, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatal(diags.Err()) - } - - if order[0] != "b" { - t.Fatalf("expected apply order [b, a], got: %v\n", order) - } -} - -// verify that dependencies are updated in the state during refresh and apply -func TestApply_updateDependencies(t *testing.T) { - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - - fooAddr := mustResourceInstanceAddr("aws_instance.foo") - barAddr := mustResourceInstanceAddr("aws_instance.bar") - bazAddr := mustResourceInstanceAddr("aws_instance.baz") - bamAddr := mustResourceInstanceAddr("aws_instance.bam") - binAddr := mustResourceInstanceAddr("aws_instance.bin") - root.SetResourceInstanceCurrent( - fooAddr.Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo"}`), - Dependencies: []addrs.ConfigResource{ - bazAddr.ContainingResource().Config(), - }, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - binAddr.Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bin","type":"aws_instance","unknown":"ok"}`), - Dependencies: []addrs.ConfigResource{ - bazAddr.ContainingResource().Config(), - }, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - bazAddr.Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"baz"}`), - Dependencies: []addrs.ConfigResource{ - // Existing dependencies should not be removed from orphaned instances - bamAddr.ContainingResource().Config(), - }, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - barAddr.Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar","foo":"foo"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "aws_instance" "bar" { - foo = aws_instance.foo.id -} - -resource "aws_instance" "foo" { -} - -resource "aws_instance" "bin" { -} -`, - }) - - p := testProvider("aws") - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - bar := plan.PriorState.ResourceInstance(barAddr) - if len(bar.Current.Dependencies) == 0 || !bar.Current.Dependencies[0].Equal(fooAddr.ContainingResource().Config()) { - t.Fatalf("bar should depend on foo after refresh, but got %s", bar.Current.Dependencies) - } - - foo := plan.PriorState.ResourceInstance(fooAddr) - if len(foo.Current.Dependencies) == 0 || !foo.Current.Dependencies[0].Equal(bazAddr.ContainingResource().Config()) { - t.Fatalf("foo should depend on baz after refresh because of the update, but got %s", foo.Current.Dependencies) - } - - bin := plan.PriorState.ResourceInstance(binAddr) - if len(bin.Current.Dependencies) != 0 { - t.Fatalf("bin should depend on nothing after refresh because there is no change, but got %s", bin.Current.Dependencies) - } - - baz := plan.PriorState.ResourceInstance(bazAddr) - if len(baz.Current.Dependencies) == 0 || !baz.Current.Dependencies[0].Equal(bamAddr.ContainingResource().Config()) { - t.Fatalf("baz should depend on bam after refresh, but got %s", baz.Current.Dependencies) - } - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatal(diags.Err()) - } - - bar = state.ResourceInstance(barAddr) - if len(bar.Current.Dependencies) == 0 || !bar.Current.Dependencies[0].Equal(fooAddr.ContainingResource().Config()) { - t.Fatalf("bar should still depend on foo after apply, but got %s", bar.Current.Dependencies) - } - - foo = state.ResourceInstance(fooAddr) - if len(foo.Current.Dependencies) != 0 { - t.Fatalf("foo should have no deps after apply, but got %s", foo.Current.Dependencies) - } - -} - -func TestContext2Apply_additionalSensitiveFromState(t *testing.T) { - // Ensure we're not trying to double-mark values decoded from state - m := testModuleInline(t, map[string]string{ - "main.tf": ` -variable "secret" { - sensitive = true - default = ["secret"] -} - -resource "test_resource" "a" { - sensitive_attr = var.secret -} - -resource "test_resource" "b" { - value = test_resource.a.id -} -`, - }) - - p := new(MockProvider) - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test_resource": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - "value": { - Type: cty.String, - Optional: true, - }, - "sensitive_attr": { - Type: cty.List(cty.String), - Optional: true, - Sensitive: true, - }, - }, - }, - }, - }) - - state := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent( - mustResourceInstanceAddr(`test_resource.a`), - &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{"id":"a","sensitive_attr":["secret"]}`), - AttrSensitivePaths: []cty.PathValueMarks{ - { - Path: cty.GetAttrPath("sensitive_attr"), - Marks: cty.NewValueMarks(marks.Sensitive), - }, - }, - Status: states.ObjectReady, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))) - assertNoErrors(t, diags) - - _, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } -} - -func TestContext2Apply_sensitiveOutputPassthrough(t *testing.T) { - // Ensure we're not trying to double-mark values decoded from state - m := testModuleInline(t, map[string]string{ - "main.tf": ` -module "mod" { - source = "./mod" -} - -resource "test_object" "a" { - test_string = module.mod.out -} -`, - - "mod/main.tf": ` -variable "in" { - sensitive = true - default = "foo" -} -output "out" { - value = var.in -} -`, - }) - - p := simpleMockProvider() - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - - obj := state.ResourceInstance(mustResourceInstanceAddr("test_object.a")) - if len(obj.Current.AttrSensitivePaths) != 1 { - t.Fatalf("Expected 1 sensitive mark for test_object.a, got %#v\n", obj.Current.AttrSensitivePaths) - } - - plan, diags = ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - // make sure the same marks are compared in the next plan as well - for _, c := range plan.Changes.Resources { - if c.Action != plans.NoOp { - t.Errorf("Unexpcetd %s change for %s", c.Action, c.Addr) - } - } -} - -func TestContext2Apply_ignoreImpureFunctionChanges(t *testing.T) { - // The impure function call should not cause a planned change with - // ignore_changes - m := testModuleInline(t, map[string]string{ - "main.tf": ` -variable "pw" { - sensitive = true - default = "foo" -} - -resource "test_object" "x" { - test_map = { - string = "X${bcrypt(var.pw)}" - } - lifecycle { - ignore_changes = [ test_map["string"] ] - } -} - -resource "test_object" "y" { - test_map = { - string = "X${bcrypt(var.pw)}" - } - lifecycle { - ignore_changes = [ test_map ] - } -} - -`, - }) - - p := simpleMockProvider() - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - assertNoErrors(t, diags) - - // FINAL PLAN: - plan, diags = ctx.Plan(m, state, SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))) - assertNoErrors(t, diags) - - // make sure the same marks are compared in the next plan as well - for _, c := range plan.Changes.Resources { - if c.Action != plans.NoOp { - t.Logf("marks before: %#v", c.BeforeValMarks) - t.Logf("marks after: %#v", c.AfterValMarks) - t.Errorf("Unexpcetd %s change for %s", c.Action, c.Addr) - } - } -} - -func TestContext2Apply_destroyWithDeposed(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "test_object" "x" { - test_string = "ok" - lifecycle { - create_before_destroy = true - } -}`, - }) - - p := simpleMockProvider() - - deposedKey := states.NewDeposedKey() - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceDeposed( - mustResourceInstanceAddr("test_object.x").Resource, - deposedKey, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectTainted, - AttrsJSON: []byte(`{"test_string":"deposed"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - if diags.HasErrors() { - t.Fatalf("plan: %s", diags.Err()) - } - - _, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("apply: %s", diags.Err()) - } - -} - -func TestContext2Apply_nullableVariables(t *testing.T) { - m := testModule(t, "apply-nullable-variables") - state := states.NewState() - ctx := testContext2(t, &ContextOpts{}) - plan, diags := ctx.Plan(m, state, &PlanOpts{}) - if diags.HasErrors() { - t.Fatalf("plan: %s", diags.Err()) - } - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("apply: %s", diags.Err()) - } - - outputs := state.Module(addrs.RootModuleInstance).OutputValues - // we check for null outputs be seeing that they don't exists - if _, ok := outputs["nullable_null_default"]; ok { - t.Error("nullable_null_default: expected no output value") - } - if _, ok := outputs["nullable_non_null_default"]; ok { - t.Error("nullable_non_null_default: expected no output value") - } - if _, ok := outputs["nullable_no_default"]; ok { - t.Error("nullable_no_default: expected no output value") - } - - if v := outputs["non_nullable_default"].Value; v.AsString() != "ok" { - t.Fatalf("incorrect 'non_nullable_default' output value: %#v\n", v) - } - if v := outputs["non_nullable_no_default"].Value; v.AsString() != "ok" { - t.Fatalf("incorrect 'non_nullable_no_default' output value: %#v\n", v) - } -} - -func TestContext2Apply_targetedDestroyWithMoved(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -module "modb" { - source = "./mod" - for_each = toset(["a", "b"]) -} -`, - "./mod/main.tf": ` -resource "test_object" "a" { -} - -module "sub" { - for_each = toset(["a", "b"]) - source = "./sub" -} - -moved { - from = module.old - to = module.sub -} -`, - "./mod/sub/main.tf": ` -resource "test_object" "s" { -} -`}) - - p := simpleMockProvider() - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - assertNoErrors(t, diags) - - // destroy only a single instance not included in the moved statements - _, diags = ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - Targets: []addrs.Targetable{mustResourceInstanceAddr(`module.modb["a"].test_object.a`)}, - }) - assertNoErrors(t, diags) -} - -func TestContext2Apply_graphError(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "test_object" "a" { - test_string = "ok" -} - -resource "test_object" "b" { - test_string = test_object.a.test_string -} -`, - }) - - p := simpleMockProvider() - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.a").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectTainted, - AttrsJSON: []byte(`{"test_string":"ok"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.b").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectTainted, - AttrsJSON: []byte(`{"test_string":"ok"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - if diags.HasErrors() { - t.Fatalf("plan: %s", diags.Err()) - } - - // We're going to corrupt the stored state so that the dependencies will - // cause a cycle when building the apply graph. - testObjA := plan.PriorState.Modules[""].Resources["test_object.a"].Instances[addrs.NoKey].Current - testObjA.Dependencies = append(testObjA.Dependencies, mustResourceInstanceAddr("test_object.b").ContainingResource().Config()) - - _, diags = ctx.Apply(plan, m) - if !diags.HasErrors() { - t.Fatal("expected cycle error from apply") - } -} - -func TestContext2Apply_resourcePostcondition(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -variable "boop" { - type = string -} - -resource "test_resource" "a" { - value = var.boop -} - -resource "test_resource" "b" { - value = test_resource.a.output - lifecycle { - postcondition { - condition = self.output != "" - error_message = "Output must not be blank." - } - } -} - -resource "test_resource" "c" { - value = test_resource.b.output -} -`, - }) - - p := testProvider("test") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test_resource": { - Attributes: map[string]*configschema.Attribute{ - "value": { - Type: cty.String, - Required: true, - }, - "output": { - Type: cty.String, - Computed: true, - }, - }, - }, - }, - }) - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { - m := req.ProposedNewState.AsValueMap() - m["output"] = cty.UnknownVal(cty.String) - - resp.PlannedState = cty.ObjectVal(m) - resp.LegacyTypeSystem = true - return resp - } - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - t.Run("condition pass", func(t *testing.T) { - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "boop": &InputValue{ - Value: cty.StringVal("boop"), - SourceType: ValueFromCLIArg, - }, - }, - }) - assertNoErrors(t, diags) - if len(plan.Changes.Resources) != 3 { - t.Fatalf("unexpected plan changes: %#v", plan.Changes) - } - - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - m := req.PlannedState.AsValueMap() - m["output"] = cty.StringVal(fmt.Sprintf("new-%s", m["value"].AsString())) - - resp.NewState = cty.ObjectVal(m) - return resp - } - state, diags := ctx.Apply(plan, m) - assertNoErrors(t, diags) - - wantResourceAttrs := map[string]struct{ value, output string }{ - "a": {"boop", "new-boop"}, - "b": {"new-boop", "new-new-boop"}, - "c": {"new-new-boop", "new-new-new-boop"}, - } - for name, attrs := range wantResourceAttrs { - addr := mustResourceInstanceAddr(fmt.Sprintf("test_resource.%s", name)) - r := state.ResourceInstance(addr) - rd, err := r.Current.Decode(cty.Object(map[string]cty.Type{ - "value": cty.String, - "output": cty.String, - })) - if err != nil { - t.Fatalf("error decoding test_resource.a: %s", err) - } - want := cty.ObjectVal(map[string]cty.Value{ - "value": cty.StringVal(attrs.value), - "output": cty.StringVal(attrs.output), - }) - if !cmp.Equal(want, rd.Value, valueComparer) { - t.Errorf("wrong attrs for %s\n%s", addr, cmp.Diff(want, rd.Value, valueComparer)) - } - } - }) - t.Run("condition fail", func(t *testing.T) { - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "boop": &InputValue{ - Value: cty.StringVal("boop"), - SourceType: ValueFromCLIArg, - }, - }, - }) - assertNoErrors(t, diags) - if len(plan.Changes.Resources) != 3 { - t.Fatalf("unexpected plan changes: %#v", plan.Changes) - } - - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - m := req.PlannedState.AsValueMap() - - // For the resource with a constraint, fudge the output to make the - // condition fail. - if value := m["value"].AsString(); value == "new-boop" { - m["output"] = cty.StringVal("") - } else { - m["output"] = cty.StringVal(fmt.Sprintf("new-%s", value)) - } - - resp.NewState = cty.ObjectVal(m) - return resp - } - state, diags := ctx.Apply(plan, m) - if !diags.HasErrors() { - t.Fatal("succeeded; want errors") - } - if got, want := diags.Err().Error(), "Resource postcondition failed: Output must not be blank."; got != want { - t.Fatalf("wrong error:\ngot: %s\nwant: %q", got, want) - } - - // Resources a and b should still be recorded in state - wantResourceAttrs := map[string]struct{ value, output string }{ - "a": {"boop", "new-boop"}, - "b": {"new-boop", ""}, - } - for name, attrs := range wantResourceAttrs { - addr := mustResourceInstanceAddr(fmt.Sprintf("test_resource.%s", name)) - r := state.ResourceInstance(addr) - rd, err := r.Current.Decode(cty.Object(map[string]cty.Type{ - "value": cty.String, - "output": cty.String, - })) - if err != nil { - t.Fatalf("error decoding test_resource.a: %s", err) - } - want := cty.ObjectVal(map[string]cty.Value{ - "value": cty.StringVal(attrs.value), - "output": cty.StringVal(attrs.output), - }) - if !cmp.Equal(want, rd.Value, valueComparer) { - t.Errorf("wrong attrs for %s\n%s", addr, cmp.Diff(want, rd.Value, valueComparer)) - } - } - - // Resource c should not be in state - if state.ResourceInstance(mustResourceInstanceAddr("test_resource.c")) != nil { - t.Error("test_resource.c should not exist in state, but is") - } - }) -} - -func TestContext2Apply_outputValuePrecondition(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` - variable "input" { - type = string - } - - module "child" { - source = "./child" - - input = var.input - } - - output "result" { - value = module.child.result - - precondition { - condition = var.input != "" - error_message = "Input must not be empty." - } - } - `, - "child/main.tf": ` - variable "input" { - type = string - } - - output "result" { - value = var.input - - precondition { - condition = var.input != "" - error_message = "Input must not be empty." - } - } - `, - }) - - checkableObjects := []addrs.Checkable{ - addrs.OutputValue{Name: "result"}.Absolute(addrs.RootModuleInstance), - addrs.OutputValue{Name: "result"}.Absolute(addrs.RootModuleInstance.Child("child", addrs.NoKey)), - } - - t.Run("pass", func(t *testing.T) { - ctx := testContext2(t, &ContextOpts{}) - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "input": &InputValue{ - Value: cty.StringVal("beep"), - SourceType: ValueFromCLIArg, - }, - }, - }) - assertNoDiagnostics(t, diags) - - for _, addr := range checkableObjects { - result := plan.Checks.GetObjectResult(addr) - if result == nil { - t.Fatalf("no check result for %s in the plan", addr) - } - if got, want := result.Status, checks.StatusPass; got != want { - t.Fatalf("wrong check status for %s during planning\ngot: %s\nwant: %s", addr, got, want) - } - } - - state, diags := ctx.Apply(plan, m) - assertNoDiagnostics(t, diags) - for _, addr := range checkableObjects { - result := state.CheckResults.GetObjectResult(addr) - if result == nil { - t.Fatalf("no check result for %s in the final state", addr) - } - if got, want := result.Status, checks.StatusPass; got != want { - t.Errorf("wrong check status for %s after apply\ngot: %s\nwant: %s", addr, got, want) - } - } - }) - - t.Run("fail", func(t *testing.T) { - // NOTE: This test actually catches a failure during planning and so - // cannot proceed to apply, so it's really more of a plan test - // than an apply test but better to keep all of these - // thematically-related test cases together. - ctx := testContext2(t, &ContextOpts{}) - _, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "input": &InputValue{ - Value: cty.StringVal(""), - SourceType: ValueFromCLIArg, - }, - }, - }) - if !diags.HasErrors() { - t.Fatalf("succeeded; want error") - } - - const wantSummary = "Module output value precondition failed" - found := false - for _, diag := range diags { - if diag.Severity() == tfdiags.Error && diag.Description().Summary == wantSummary { - found = true - break - } - } - - if !found { - t.Fatalf("missing expected error\nwant summary: %s\ngot: %s", wantSummary, diags.Err().Error()) - } - }) -} - -func TestContext2Apply_resourceConditionApplyTimeFail(t *testing.T) { - // This tests the less common situation where a condition fails due to - // a change in a resource other than the one the condition is attached to, - // and the condition result is unknown during planning. - // - // This edge case is a tricky one because it relies on Terraform still - // visiting test_resource.b (in the configuration below) to evaluate - // its conditions even though there aren't any changes directly planned - // for it, so that we can consider whether changes to test_resource.a - // have changed the outcome. - - m := testModuleInline(t, map[string]string{ - "main.tf": ` - variable "input" { - type = string - } - - resource "test_resource" "a" { - value = var.input - } - - resource "test_resource" "b" { - value = "beep" - - lifecycle { - postcondition { - condition = test_resource.a.output == self.output - error_message = "Outputs must match." - } - } - } - `, - }) - - p := testProvider("test") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test_resource": { - Attributes: map[string]*configschema.Attribute{ - "value": { - Type: cty.String, - Required: true, - }, - "output": { - Type: cty.String, - Computed: true, - }, - }, - }, - }, - }) - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { - // Whenever "value" changes, "output" follows it during the apply step, - // but is initially unknown during the plan step. - - m := req.ProposedNewState.AsValueMap() - priorVal := cty.NullVal(cty.String) - if !req.PriorState.IsNull() { - priorVal = req.PriorState.GetAttr("value") - } - if m["output"].IsNull() || !priorVal.RawEquals(m["value"]) { - m["output"] = cty.UnknownVal(cty.String) - } - - resp.PlannedState = cty.ObjectVal(m) - resp.LegacyTypeSystem = true - return resp - } - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - m := req.PlannedState.AsValueMap() - m["output"] = m["value"] - resp.NewState = cty.ObjectVal(m) - return resp - } - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - instA := mustResourceInstanceAddr("test_resource.a") - instB := mustResourceInstanceAddr("test_resource.b") - - // Preparation: an initial plan and apply with a correct input variable - // should succeed and give us a valid and complete state to use for the - // subsequent plan and apply that we'll expect to fail. - var prevRunState *states.State - { - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "input": &InputValue{ - Value: cty.StringVal("beep"), - SourceType: ValueFromCLIArg, - }, - }, - }) - assertNoErrors(t, diags) - planA := plan.Changes.ResourceInstance(instA) - if planA == nil || planA.Action != plans.Create { - t.Fatalf("incorrect initial plan for instance A\nwant a 'create' change\ngot: %s", spew.Sdump(planA)) - } - planB := plan.Changes.ResourceInstance(instB) - if planB == nil || planB.Action != plans.Create { - t.Fatalf("incorrect initial plan for instance B\nwant a 'create' change\ngot: %s", spew.Sdump(planB)) - } - - state, diags := ctx.Apply(plan, m) - assertNoErrors(t, diags) - - stateA := state.ResourceInstance(instA) - if stateA == nil || stateA.Current == nil || !bytes.Contains(stateA.Current.AttrsJSON, []byte(`"beep"`)) { - t.Fatalf("incorrect initial state for instance A\ngot: %s", spew.Sdump(stateA)) - } - stateB := state.ResourceInstance(instB) - if stateB == nil || stateB.Current == nil || !bytes.Contains(stateB.Current.AttrsJSON, []byte(`"beep"`)) { - t.Fatalf("incorrect initial state for instance B\ngot: %s", spew.Sdump(stateB)) - } - prevRunState = state - } - - // Now we'll run another plan and apply with a different value for - // var.input that should cause the test_resource.b condition to be unknown - // during planning and then fail during apply. - { - plan, diags := ctx.Plan(m, prevRunState, &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "input": &InputValue{ - Value: cty.StringVal("boop"), // NOTE: This has changed - SourceType: ValueFromCLIArg, - }, - }, - }) - assertNoErrors(t, diags) - planA := plan.Changes.ResourceInstance(instA) - if planA == nil || planA.Action != plans.Update { - t.Fatalf("incorrect initial plan for instance A\nwant an 'update' change\ngot: %s", spew.Sdump(planA)) - } - planB := plan.Changes.ResourceInstance(instB) - if planB == nil || planB.Action != plans.NoOp { - t.Fatalf("incorrect initial plan for instance B\nwant a 'no-op' change\ngot: %s", spew.Sdump(planB)) - } - - _, diags = ctx.Apply(plan, m) - if !diags.HasErrors() { - t.Fatal("final apply succeeded, but should've failed with a postcondition error") - } - if len(diags) != 1 { - t.Fatalf("expected exactly one diagnostic, but got: %s", diags.Err().Error()) - } - if got, want := diags[0].Description().Summary, "Resource postcondition failed"; got != want { - t.Fatalf("wrong diagnostic summary\ngot: %s\nwant: %s", got, want) - } - } -} - -// pass an input through some expanded values, and back to a provider to make -// sure we can fully evaluate a provider configuration during a destroy plan. -func TestContext2Apply_destroyWithConfiguredProvider(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -variable "in" { - type = map(string) - default = { - "a" = "first" - "b" = "second" - } -} - -module "mod" { - source = "./mod" - for_each = var.in - in = each.value -} - -locals { - config = [for each in module.mod : each.out] -} - -provider "other" { - output = [for each in module.mod : each.out] - local = local.config - var = var.in -} - -resource "other_object" "other" { -} -`, - "./mod/main.tf": ` -variable "in" { - type = string -} - -data "test_object" "d" { - test_string = var.in -} - -resource "test_object" "a" { - test_string = var.in -} - -output "out" { - value = data.test_object.d.output -} -`}) - - testProvider := &MockProvider{ - GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{ - Provider: providers.Schema{Block: simpleTestSchema()}, - ResourceTypes: map[string]providers.Schema{ - "test_object": providers.Schema{Block: simpleTestSchema()}, - }, - DataSources: map[string]providers.Schema{ - "test_object": providers.Schema{ - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "test_string": { - Type: cty.String, - Optional: true, - }, - "output": { - Type: cty.String, - Computed: true, - }, - }, - }, - }, - }, - }, - } - - testProvider.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) { - cfg := req.Config.AsValueMap() - s := cfg["test_string"].AsString() - if !strings.Contains("firstsecond", s) { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("expected 'first' or 'second', got %s", s)) - return resp - } - - cfg["output"] = cty.StringVal(s + "-ok") - resp.State = cty.ObjectVal(cfg) - return resp - } - - otherProvider := &MockProvider{ - GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{ - Provider: providers.Schema{ - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "output": { - Type: cty.List(cty.String), - Optional: true, - }, - "local": { - Type: cty.List(cty.String), - Optional: true, - }, - "var": { - Type: cty.Map(cty.String), - Optional: true, - }, - }, - }, - }, - ResourceTypes: map[string]providers.Schema{ - "other_object": providers.Schema{Block: simpleTestSchema()}, - }, - }, - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(testProvider), - addrs.NewDefaultProvider("other"): testProviderFuncFixed(otherProvider), - }, - }) - - opts := SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)) - plan, diags := ctx.Plan(m, states.NewState(), opts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - assertNoErrors(t, diags) - - // Resource changes which have dependencies across providers which - // themselves depend on resources can result in cycles. - // Because other_object transitively depends on the module resources - // through its provider, we trigger changes on both sides of this boundary - // to ensure we can create a valid plan. - // - // Taint the object to make sure a replacement works in the plan. - otherObjAddr := mustResourceInstanceAddr("other_object.other") - otherObj := state.ResourceInstance(otherObjAddr) - otherObj.Current.Status = states.ObjectTainted - // Force a change which needs to be reverted. - testObjAddr := mustResourceInstanceAddr(`module.mod["a"].test_object.a`) - testObjA := state.ResourceInstance(testObjAddr) - testObjA.Current.AttrsJSON = []byte(`{"test_bool":null,"test_list":null,"test_map":null,"test_number":null,"test_string":"changed"}`) - - _, diags = ctx.Plan(m, state, opts) - assertNoErrors(t, diags) - return - - otherProvider.ConfigureProviderCalled = false - otherProvider.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) { - // check that our config is complete, even during a destroy plan - expected := cty.ObjectVal(map[string]cty.Value{ - "local": cty.ListVal([]cty.Value{cty.StringVal("first-ok"), cty.StringVal("second-ok")}), - "output": cty.ListVal([]cty.Value{cty.StringVal("first-ok"), cty.StringVal("second-ok")}), - "var": cty.MapVal(map[string]cty.Value{ - "a": cty.StringVal("first"), - "b": cty.StringVal("second"), - }), - }) - - if !req.Config.RawEquals(expected) { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf( - `incorrect provider config: -expected: %#v -got: %#v`, - expected, req.Config)) - } - - return resp - } - - opts.Mode = plans.DestroyMode - // skip refresh so that we don't configure the provider before the destroy plan - opts.SkipRefresh = true - - // destroy only a single instance not included in the moved statements - _, diags = ctx.Plan(m, state, opts) - assertNoErrors(t, diags) - - if !otherProvider.ConfigureProviderCalled { - t.Fatal("failed to configure provider during destroy plan") - } -} - -// check that a provider can verify a planned destroy -func TestContext2Apply_plannedDestroy(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "test_object" "x" { - test_string = "ok" -}`, - }) - - p := simpleMockProvider() - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { - if !req.ProposedNewState.IsNull() { - // we should only be destroying in this test - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("unexpected plan with %#v", req.ProposedNewState)) - return resp - } - - resp.PlannedState = req.ProposedNewState - // we're going to verify the destroy plan by inserting private data required for destroy - resp.PlannedPrivate = append(resp.PlannedPrivate, []byte("planned")...) - return resp - } - - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - // if the value is nil, we return that directly to correspond to a delete - if !req.PlannedState.IsNull() { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("unexpected apply with %#v", req.PlannedState)) - return resp - } - - resp.NewState = req.PlannedState - - // make sure we get our private data from the plan - private := string(req.PlannedPrivate) - if private != "planned" { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("missing private data from plan, got %q", private)) - } - return resp - } - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.x").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"test_string":"ok"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - // we don't want to refresh, because that actually runs a normal plan - SkipRefresh: true, - }) - if diags.HasErrors() { - t.Fatalf("plan: %s", diags.Err()) - } - - _, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("apply: %s", diags.Err()) - } -} - -func TestContext2Apply_missingOrphanedResource(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -# changed resource address to create a new object -resource "test_object" "y" { - test_string = "y" -} -`, - }) - - p := simpleMockProvider() - - // report the prior value is missing - p.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) { - resp.NewState = cty.NullVal(req.PriorState.Type()) - return resp - } - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.x").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"test_string":"x"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - opts := SimplePlanOpts(plans.NormalMode, nil) - plan, diags := ctx.Plan(m, state, opts) - assertNoErrors(t, diags) - - _, diags = ctx.Apply(plan, m) - assertNoErrors(t, diags) -} - -// Outputs should not cause evaluation errors during destroy -// Check eval from both root level outputs and module outputs, which are -// handled differently during apply. -func TestContext2Apply_outputsNotToEvaluate(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -module "mod" { - source = "./mod" - cond = false -} - -output "from_resource" { - value = module.mod.from_resource -} - -output "from_data" { - value = module.mod.from_data -} -`, - - "./mod/main.tf": ` -variable "cond" { - type = bool -} - -module "mod" { - source = "../mod2/" - cond = var.cond -} - -output "from_resource" { - value = module.mod.resource -} - -output "from_data" { - value = module.mod.data -} -`, - - "./mod2/main.tf": ` -variable "cond" { - type = bool -} - -resource "test_object" "x" { - count = var.cond ? 0:1 -} - -data "test_object" "d" { - count = var.cond ? 0:1 -} - -output "resource" { - value = var.cond ? null : test_object.x.*.test_string[0] -} - -output "data" { - value = one(data.test_object.d[*].test_string) -} -`}) - - p := simpleMockProvider() - p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) { - resp.State = req.Config - return resp - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - // apply the state - opts := SimplePlanOpts(plans.NormalMode, nil) - plan, diags := ctx.Plan(m, states.NewState(), opts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - assertNoErrors(t, diags) - - // and destroy - opts = SimplePlanOpts(plans.DestroyMode, nil) - plan, diags = ctx.Plan(m, state, opts) - assertNoErrors(t, diags) - - state, diags = ctx.Apply(plan, m) - assertNoErrors(t, diags) - - // and destroy again with no state - if !state.Empty() { - t.Fatal("expected empty state, got", state) - } - - opts = SimplePlanOpts(plans.DestroyMode, nil) - plan, diags = ctx.Plan(m, state, opts) - assertNoErrors(t, diags) - - _, diags = ctx.Apply(plan, m) - assertNoErrors(t, diags) -} - -// don't evaluate conditions on outputs when destroying -func TestContext2Apply_noOutputChecksOnDestroy(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -module "mod" { - source = "./mod" -} - -output "from_resource" { - value = module.mod.from_resource -} -`, - - "./mod/main.tf": ` -resource "test_object" "x" { - test_string = "wrong val" -} - -output "from_resource" { - value = test_object.x.test_string - precondition { - condition = test_object.x.test_string == "ok" - error_message = "resource error" - } -} -`}) - - p := simpleMockProvider() - - state := states.NewState() - mod := state.EnsureModule(addrs.RootModuleInstance.Child("mod", addrs.NoKey)) - mod.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.x").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"test_string":"wrong_val"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - opts := SimplePlanOpts(plans.DestroyMode, nil) - plan, diags := ctx.Plan(m, state, opts) - assertNoErrors(t, diags) - - _, diags = ctx.Apply(plan, m) - assertNoErrors(t, diags) -} - -// -refresh-only should update checks -func TestContext2Apply_refreshApplyUpdatesChecks(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "test_object" "x" { - test_string = "ok" - lifecycle { - postcondition { - condition = self.test_string == "ok" - error_message = "wrong val" - } - } -} - -output "from_resource" { - value = test_object.x.test_string - precondition { - condition = test_object.x.test_string == "ok" - error_message = "wrong val" - } -} -`}) - - p := simpleMockProvider() - p.ReadResourceResponse = &providers.ReadResourceResponse{ - NewState: cty.ObjectVal(map[string]cty.Value{ - "test_string": cty.StringVal("ok"), - }), - } - - state := states.NewState() - mod := state.EnsureModule(addrs.RootModuleInstance) - mod.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.x").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"test_string":"wrong val"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - mod.SetOutputValue("from_resource", cty.StringVal("wrong val"), false) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - opts := SimplePlanOpts(plans.RefreshOnlyMode, nil) - plan, diags := ctx.Plan(m, state, opts) - assertNoErrors(t, diags) - - state, diags = ctx.Apply(plan, m) - assertNoErrors(t, diags) - - resCheck := state.CheckResults.GetObjectResult(mustResourceInstanceAddr("test_object.x")) - if resCheck.Status != checks.StatusPass { - t.Fatalf("unexpected check %s: %s\n", resCheck.Status, resCheck.FailureMessages) - } - - outAddr := addrs.AbsOutputValue{ - Module: addrs.RootModuleInstance, - OutputValue: addrs.OutputValue{ - Name: "from_resource", - }, - } - outCheck := state.CheckResults.GetObjectResult(outAddr) - if outCheck.Status != checks.StatusPass { - t.Fatalf("unexpected check %s: %s\n", outCheck.Status, outCheck.FailureMessages) - } -} - -// NoOp changes may have conditions to evaluate, but should not re-plan and -// apply the entire resource. -func TestContext2Apply_noRePlanNoOp(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "test_object" "x" { -} - -resource "test_object" "y" { - # test_object.w is being re-created, so this precondition must be evaluated - # during apply, however this resource should otherwise be a NoOp. - lifecycle { - precondition { - condition = test_object.x.test_string == null - error_message = "test_object.x.test_string should be null" - } - } -} -`}) - - p := simpleMockProvider() - // make sure we can compute the attr - testString := p.GetProviderSchemaResponse.ResourceTypes["test_object"].Block.Attributes["test_string"] - testString.Computed = true - testString.Optional = false - - yAddr := mustResourceInstanceAddr("test_object.y") - - state := states.NewState() - mod := state.RootModule() - mod.SetResourceInstanceCurrent( - yAddr.Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"test_string":"y"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - opts := SimplePlanOpts(plans.NormalMode, nil) - plan, diags := ctx.Plan(m, state, opts) - assertNoErrors(t, diags) - - for _, c := range plan.Changes.Resources { - if c.Addr.Equal(yAddr) && c.Action != plans.NoOp { - t.Fatalf("unexpected %s change for test_object.y", c.Action) - } - } - - // test_object.y is a NoOp change from the plan, but is included in the - // graph due to the conditions which must be evaluated. This however should - // not cause the resource to be re-planned. - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { - testString := req.ProposedNewState.GetAttr("test_string") - if !testString.IsNull() && testString.AsString() == "y" { - resp.Diagnostics = resp.Diagnostics.Append(errors.New("Unexpected apply-time plan for test_object.y. Original plan was a NoOp")) - } - resp.PlannedState = req.ProposedNewState - return resp - } - - _, diags = ctx.Apply(plan, m) - assertNoErrors(t, diags) -} - -// ensure all references from preconditions are tracked through plan and apply -func TestContext2Apply_preconditionErrorMessageRef(t *testing.T) { - p := testProvider("test") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - m := testModuleInline(t, map[string]string{ - "main.tf": ` -module "nested" { - source = "./mod" -} - -output "nested_a" { - value = module.nested.a -} -`, - - "mod/main.tf": ` -variable "boop" { - default = "boop" -} - -variable "msg" { - default = "Incorrect boop." -} - -output "a" { - value = "x" - - precondition { - condition = var.boop == "boop" - error_message = var.msg - } -} -`, - }) - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - }) - assertNoErrors(t, diags) - _, diags = ctx.Apply(plan, m) - assertNoErrors(t, diags) -} - -func TestContext2Apply_destroyNullModuleOutput(t *testing.T) { - p := testProvider("test") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - m := testModuleInline(t, map[string]string{ - "main.tf": ` -module "null_module" { - source = "./mod" -} - -locals { - module_output = module.null_module.null_module_test -} - -output "test_root" { - value = module.null_module.test_output -} - -output "root_module" { - value = local.module_output #fails -} -`, - - "mod/main.tf": ` -output "test_output" { - value = "test" -} - -output "null_module_test" { - value = null -} -`, - }) - - // verify plan and apply - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - }) - assertNoErrors(t, diags) - state, diags := ctx.Apply(plan, m) - assertNoErrors(t, diags) - - // now destroy - plan, diags = ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - assertNoErrors(t, diags) - _, diags = ctx.Apply(plan, m) - assertNoErrors(t, diags) -} - -func TestContext2Apply_moduleOutputWithSensitiveAttrs(t *testing.T) { - // Ensure that nested sensitive marks are stored when accessing non-root - // module outputs, and that they do not cause the entire output value to - // become sensitive. - m := testModuleInline(t, map[string]string{ - "main.tf": ` -module "mod" { - source = "./mod" -} - -resource "test_resource" "b" { - // if the module output were wholly sensitive it would not be valid to use in - // for_each - for_each = module.mod.resources - value = each.value.output -} - -output "root_output" { - // The root output cannot contain any sensitive marks at all. - // Applying nonsensitive would fail here if the nested sensitive mark were - // not maintained through the output. - value = [ for k, v in module.mod.resources : nonsensitive(v.output) ] -} -`, - "./mod/main.tf": ` -resource "test_resource" "a" { - for_each = {"key": "value"} - value = each.key -} - -output "resources" { - value = test_resource.a -} -`, - }) - - p := testProvider("test") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test_resource": { - Attributes: map[string]*configschema.Attribute{ - "value": { - Type: cty.String, - Required: true, - }, - "output": { - Type: cty.String, - Sensitive: true, - Computed: true, - }, - }, - }, - }, - }) - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - }) - assertNoErrors(t, diags) - _, diags = ctx.Apply(plan, m) - assertNoErrors(t, diags) -} diff --git a/internal/terraform/context_apply_test.go b/internal/terraform/context_apply_test.go deleted file mode 100644 index 4f16453310ee..000000000000 --- a/internal/terraform/context_apply_test.go +++ /dev/null @@ -1,12632 +0,0 @@ -package terraform - -import ( - "bytes" - "encoding/json" - "errors" - "fmt" - "log" - "reflect" - "runtime" - "sort" - "strings" - "sync" - "sync/atomic" - "testing" - "time" - - "github.com/davecgh/go-spew/spew" - "github.com/go-test/deep" - "github.com/google/go-cmp/cmp" - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/gocty" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/configs/hcl2shim" - "github.com/hashicorp/terraform/internal/lang/marks" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/provisioners" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -func TestContext2Apply_basic(t *testing.T) { - m := testModule(t, "apply-good") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - mod := state.RootModule() - if len(mod.Resources) < 2 { - t.Fatalf("bad: %#v", mod.Resources) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestContext2Apply_unstable(t *testing.T) { - // This tests behavior when the configuration contains an unstable value, - // such as the result of uuid() or timestamp(), where each call produces - // a different result. - // - // This is an important case to test because we need to ensure that - // we don't re-call the function during the apply phase: the value should - // be fixed during plan - - m := testModule(t, "apply-unstable") - p := testProvider("test") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected error during Plan: %s", diags.Err()) - } - - addr := addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_resource", - Name: "foo", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance) - schema := p.GetProviderSchemaResponse.ResourceTypes["test_resource"].Block - rds := plan.Changes.ResourceInstance(addr) - rd, err := rds.Decode(schema.ImpliedType()) - if err != nil { - t.Fatal(err) - } - if rd.After.GetAttr("random").IsKnown() { - t.Fatalf("Attribute 'random' has known value %#v; should be unknown in plan", rd.After.GetAttr("random")) - } - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("unexpected error during Apply: %s", diags.Err()) - } - - mod := state.Module(addr.Module) - rss := state.ResourceInstance(addr) - - if len(mod.Resources) != 1 { - t.Fatalf("wrong number of resources %d; want 1", len(mod.Resources)) - } - - rs, err := rss.Current.Decode(schema.ImpliedType()) - if err != nil { - t.Fatalf("decode error: %v", err) - } - got := rs.Value.GetAttr("random") - if !got.IsKnown() { - t.Fatalf("random is still unknown after apply") - } - if got, want := len(got.AsString()), 36; got != want { - t.Fatalf("random string has wrong length %d; want %d", got, want) - } -} - -func TestContext2Apply_escape(t *testing.T) { - m := testModule(t, "apply-escape") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - checkStateString(t, state, ` -aws_instance.bar: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = "bar" - type = aws_instance -`) -} - -func TestContext2Apply_resourceCountOneList(t *testing.T) { - m := testModule(t, "apply-resource-count-one-list") - p := testProvider("null") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("null"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - assertNoDiagnostics(t, diags) - - got := strings.TrimSpace(state.String()) - want := strings.TrimSpace(`null_resource.foo.0: - ID = foo - provider = provider["registry.terraform.io/hashicorp/null"] - -Outputs: - -test = [foo]`) - if got != want { - t.Fatalf("got:\n%s\n\nwant:\n%s\n", got, want) - } -} -func TestContext2Apply_resourceCountZeroList(t *testing.T) { - m := testModule(t, "apply-resource-count-zero-list") - p := testProvider("null") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("null"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - got := strings.TrimSpace(state.String()) - want := strings.TrimSpace(` -Outputs: - -test = []`) - if got != want { - t.Fatalf("wrong state\n\ngot:\n%s\n\nwant:\n%s\n", got, want) - } -} - -func TestContext2Apply_resourceDependsOnModule(t *testing.T) { - m := testModule(t, "apply-resource-depends-on-module") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - // verify the apply happens in the correct order - var mu sync.Mutex - var order []string - - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - ami := req.PlannedState.GetAttr("ami").AsString() - switch ami { - case "child": - - // make the child slower than the parent - time.Sleep(50 * time.Millisecond) - - mu.Lock() - order = append(order, "child") - mu.Unlock() - case "parent": - mu.Lock() - order = append(order, "parent") - mu.Unlock() - } - - return testApplyFn(req) - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - if !reflect.DeepEqual(order, []string{"child", "parent"}) { - t.Fatal("resources applied out of order") - } - - checkStateString(t, state, testTerraformApplyResourceDependsOnModuleStr) -} - -// Test that without a config, the Dependencies in the state are enough -// to maintain proper ordering. -func TestContext2Apply_resourceDependsOnModuleStateOnly(t *testing.T) { - m := testModule(t, "apply-resource-depends-on-module-empty") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.a").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"parent"}`), - Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("module.child.aws_instance.child")}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey)) - child.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.child").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"child"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - { - // verify the apply happens in the correct order - var mu sync.Mutex - var order []string - - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - id := req.PriorState.GetAttr("id") - if id.IsKnown() && id.AsString() == "parent" { - // make the dep slower than the parent - time.Sleep(50 * time.Millisecond) - - mu.Lock() - order = append(order, "child") - mu.Unlock() - } else { - mu.Lock() - order = append(order, "parent") - mu.Unlock() - } - - return testApplyFn(req) - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - assertNoErrors(t, diags) - - if !reflect.DeepEqual(order, []string{"child", "parent"}) { - t.Fatal("resources applied out of order") - } - - checkStateString(t, state, "") - } -} - -func TestContext2Apply_resourceDependsOnModuleDestroy(t *testing.T) { - m := testModule(t, "apply-resource-depends-on-module") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - var globalState *states.State - { - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - globalState = state - } - - { - // Wait for the dependency, sleep, and verify the graph never - // called a child. - var called int32 - var checked bool - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - ami := req.PriorState.GetAttr("ami").AsString() - if ami == "parent" { - checked = true - - // Sleep to allow parallel execution - time.Sleep(50 * time.Millisecond) - - // Verify that called is 0 (dep not called) - if atomic.LoadInt32(&called) != 0 { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("module child should not be called")) - return resp - } - } - - atomic.AddInt32(&called, 1) - return testApplyFn(req) - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, globalState, &PlanOpts{ - Mode: plans.DestroyMode, - }) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - if !checked { - t.Fatal("should check") - } - - checkStateString(t, state, ``) - } -} - -func TestContext2Apply_resourceDependsOnModuleGrandchild(t *testing.T) { - m := testModule(t, "apply-resource-depends-on-module-deep") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - { - // Wait for the dependency, sleep, and verify the graph never - // called a child. - var called int32 - var checked bool - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - planned := req.PlannedState.AsValueMap() - if ami, ok := planned["ami"]; ok && ami.AsString() == "grandchild" { - checked = true - - // Sleep to allow parallel execution - time.Sleep(50 * time.Millisecond) - - // Verify that called is 0 (dep not called) - if atomic.LoadInt32(&called) != 0 { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("aws_instance.a should not be called")) - return resp - } - } - - atomic.AddInt32(&called, 1) - return testApplyFn(req) - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - if !checked { - t.Fatal("should check") - } - - checkStateString(t, state, testTerraformApplyResourceDependsOnModuleDeepStr) - } -} - -func TestContext2Apply_resourceDependsOnModuleInModule(t *testing.T) { - m := testModule(t, "apply-resource-depends-on-module-in-module") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - { - // Wait for the dependency, sleep, and verify the graph never - // called a child. - var called int32 - var checked bool - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - planned := req.PlannedState.AsValueMap() - if ami, ok := planned["ami"]; ok && ami.AsString() == "grandchild" { - checked = true - - // Sleep to allow parallel execution - time.Sleep(50 * time.Millisecond) - - // Verify that called is 0 (dep not called) - if atomic.LoadInt32(&called) != 0 { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("something else was applied before grandchild; grandchild should be first")) - return resp - } - } - - atomic.AddInt32(&called, 1) - return testApplyFn(req) - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - if !checked { - t.Fatal("should check") - } - - checkStateString(t, state, testTerraformApplyResourceDependsOnModuleInModuleStr) - } -} - -func TestContext2Apply_mapVarBetweenModules(t *testing.T) { - m := testModule(t, "apply-map-var-through-module") - p := testProvider("null") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("null"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(` -Outputs: - -amis_from_module = {eu-west-1:ami-789012 eu-west-2:ami-989484 us-west-1:ami-123456 us-west-2:ami-456789 } - -module.test: - null_resource.noop: - ID = foo - provider = provider["registry.terraform.io/hashicorp/null"] - - Outputs: - - amis_out = {eu-west-1:ami-789012 eu-west-2:ami-989484 us-west-1:ami-123456 us-west-2:ami-456789 }`) - if actual != expected { - t.Fatalf("expected: \n%s\n\ngot: \n%s\n", expected, actual) - } -} - -func TestContext2Apply_refCount(t *testing.T) { - m := testModule(t, "apply-ref-count") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - mod := state.RootModule() - if len(mod.Resources) < 2 { - t.Fatalf("bad: %#v", mod.Resources) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyRefCountStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestContext2Apply_providerAlias(t *testing.T) { - m := testModule(t, "apply-provider-alias") - - // Each provider instance must be completely independent to ensure that we - // are verifying the correct state of each. - p := func() (providers.Interface, error) { - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - return p, nil - } - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): p, - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - mod := state.RootModule() - if len(mod.Resources) < 2 { - t.Fatalf("bad: %#v", mod.Resources) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyProviderAliasStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -// Two providers that are configured should both be configured prior to apply -func TestContext2Apply_providerAliasConfigure(t *testing.T) { - m := testModule(t, "apply-provider-alias-configure") - - // Each provider instance must be completely independent to ensure that we - // are verifying the correct state of each. - p := func() (providers.Interface, error) { - p := testProvider("another") - p.ApplyResourceChangeFn = testApplyFn - p.PlanResourceChangeFn = testDiffFn - return p, nil - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("another"): p, - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } else { - t.Logf(legacyDiffComparisonString(plan.Changes)) - } - - // Configure to record calls AFTER Plan above - var configCount int32 - p = func() (providers.Interface, error) { - p := testProvider("another") - p.ApplyResourceChangeFn = testApplyFn - p.PlanResourceChangeFn = testDiffFn - p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) { - atomic.AddInt32(&configCount, 1) - - foo := req.Config.GetAttr("foo").AsString() - if foo != "bar" { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("foo: %#v", foo)) - } - - return - } - return p, nil - } - - ctx = testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("another"): p, - }, - }) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - if configCount != 2 { - t.Fatalf("provider config expected 2 calls, got: %d", configCount) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyProviderAliasConfigStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -// GH-2870 -func TestContext2Apply_providerWarning(t *testing.T) { - m := testModule(t, "apply-provider-warning") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - p.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) (resp providers.ValidateResourceConfigResponse) { - resp.Diagnostics = resp.Diagnostics.Append(tfdiags.SimpleWarning("just a warning")) - return - } - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(` -aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance - `) - if actual != expected { - t.Fatalf("got: \n%s\n\nexpected:\n%s", actual, expected) - } - - if !p.ConfigureProviderCalled { - t.Fatalf("provider Configure() was never called!") - } -} - -func TestContext2Apply_emptyModule(t *testing.T) { - // A module with only outputs (no resources) - m := testModule(t, "apply-empty-module") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - actual := strings.TrimSpace(state.String()) - actual = strings.Replace(actual, " ", "", -1) - expected := strings.TrimSpace(testTerraformApplyEmptyModuleStr) - if actual != expected { - t.Fatalf("bad: \n%s\nexpect:\n%s", actual, expected) - } -} - -func TestContext2Apply_createBeforeDestroy(t *testing.T) { - m := testModule(t, "apply-good-create-before") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar", "require_new": "abc"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } else { - t.Logf(legacyDiffComparisonString(plan.Changes)) - } - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - mod := state.RootModule() - if got, want := len(mod.Resources), 1; got != want { - t.Logf("state:\n%s", state) - t.Fatalf("wrong number of resources %d; want %d", got, want) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyCreateBeforeStr) - if actual != expected { - t.Fatalf("expected:\n%s\ngot:\n%s", expected, actual) - } -} - -func TestContext2Apply_createBeforeDestroyUpdate(t *testing.T) { - m := testModule(t, "apply-good-create-before-update") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - // signal that resource foo has started applying - fooChan := make(chan struct{}) - - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - id := req.PriorState.GetAttr("id").AsString() - switch id { - case "bar": - select { - case <-fooChan: - resp.Diagnostics = resp.Diagnostics.Append(errors.New("bar must be updated before foo is destroyed")) - return resp - case <-time.After(100 * time.Millisecond): - // wait a moment to ensure that foo is not going to be destroyed first - } - case "foo": - close(fooChan) - } - - return testApplyFn(req) - } - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - fooAddr := mustResourceInstanceAddr("aws_instance.foo") - root.SetResourceInstanceCurrent( - fooAddr.Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo","foo":"bar"}`), - CreateBeforeDestroy: true, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar","foo":"bar"}`), - CreateBeforeDestroy: true, - Dependencies: []addrs.ConfigResource{fooAddr.ContainingResource().Config()}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } else { - t.Logf(legacyDiffComparisonString(plan.Changes)) - } - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - mod := state.RootModule() - if len(mod.Resources) != 1 { - t.Fatalf("bad: %s", state) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyCreateBeforeUpdateStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -// This tests that when a CBD resource depends on a non-CBD resource, -// we can still properly apply changes that require new for both. -func TestContext2Apply_createBeforeDestroy_dependsNonCBD(t *testing.T) { - m := testModule(t, "apply-cbd-depends-non-cbd") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar", "require_new": "abc"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo", "require_new": "abc"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } else { - t.Logf(legacyDiffComparisonString(plan.Changes)) - } - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - checkStateString(t, state, ` -aws_instance.bar: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - require_new = yes - type = aws_instance - value = foo - - Dependencies: - aws_instance.foo -aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - require_new = yes - type = aws_instance - `) -} - -func TestContext2Apply_createBeforeDestroy_hook(t *testing.T) { - h := new(MockHook) - m := testModule(t, "apply-good-create-before") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar", "require_new": "abc"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - var actual []cty.Value - var actualLock sync.Mutex - h.PostApplyFn = func(addr addrs.AbsResourceInstance, gen states.Generation, sv cty.Value, e error) (HookAction, error) { - actualLock.Lock() - - defer actualLock.Unlock() - actual = append(actual, sv) - return HookActionContinue, nil - } - - ctx := testContext2(t, &ContextOpts{ - Hooks: []Hook{h}, - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } else { - t.Logf(legacyDiffComparisonString(plan.Changes)) - } - - if _, diags := ctx.Apply(plan, m); diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } - - expected := []cty.Value{ - cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("foo"), - "require_new": cty.StringVal("xyz"), - "type": cty.StringVal("aws_instance"), - }), - cty.NullVal(cty.DynamicPseudoType), - } - - cmpOpt := cmp.Transformer("ctyshim", hcl2shim.ConfigValueFromHCL2) - if !cmp.Equal(actual, expected, cmpOpt) { - t.Fatalf("wrong state snapshot sequence\n%s", cmp.Diff(expected, actual, cmpOpt)) - } -} - -// Test that we can perform an apply with CBD in a count with deposed instances. -func TestContext2Apply_createBeforeDestroy_deposedCount(t *testing.T) { - m := testModule(t, "apply-cbd-count") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar[0]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectTainted, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceDeposed( - mustResourceInstanceAddr("aws_instance.bar[0]").Resource, - states.NewDeposedKey(), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectTainted, - AttrsJSON: []byte(`{"id":"foo"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar[1]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectTainted, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceDeposed( - mustResourceInstanceAddr("aws_instance.bar[1]").Resource, - states.NewDeposedKey(), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectTainted, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } else { - t.Logf(legacyDiffComparisonString(plan.Changes)) - } - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - checkStateString(t, state, ` -aws_instance.bar.0: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = bar - type = aws_instance -aws_instance.bar.1: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = bar - type = aws_instance - `) -} - -// Test that when we have a deposed instance but a good primary, we still -// destroy the deposed instance. -func TestContext2Apply_createBeforeDestroy_deposedOnly(t *testing.T) { - m := testModule(t, "apply-cbd-deposed-only") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceDeposed( - mustResourceInstanceAddr("aws_instance.bar").Resource, - states.NewDeposedKey(), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectTainted, - AttrsJSON: []byte(`{"id":"foo"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } else { - t.Logf(legacyDiffComparisonString(plan.Changes)) - } - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - checkStateString(t, state, ` -aws_instance.bar: - ID = bar - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance - `) -} - -func TestContext2Apply_destroyComputed(t *testing.T) { - m := testModule(t, "apply-destroy-computed") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo", "output": "value"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - if diags.HasErrors() { - logDiagnostics(t, diags) - t.Fatal("plan failed") - } else { - t.Logf("plan:\n\n%s", legacyDiffComparisonString(plan.Changes)) - } - - if _, diags := ctx.Apply(plan, m); diags.HasErrors() { - logDiagnostics(t, diags) - t.Fatal("apply failed") - } -} - -// Test that the destroy operation uses depends_on as a source of ordering. -func TestContext2Apply_destroyDependsOn(t *testing.T) { - // It is possible for this to be racy, so we loop a number of times - // just to check. - for i := 0; i < 10; i++ { - testContext2Apply_destroyDependsOn(t) - } -} - -func testContext2Apply_destroyDependsOn(t *testing.T) { - m := testModule(t, "apply-destroy-depends-on") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo"}`), - Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.bar")}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - // Record the order we see Apply - var actual []string - var actualLock sync.Mutex - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse { - actualLock.Lock() - defer actualLock.Unlock() - id := req.PriorState.GetAttr("id").AsString() - actual = append(actual, id) - - return testApplyFn(req) - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Parallelism: 1, // To check ordering - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - assertNoErrors(t, diags) - - if _, diags := ctx.Apply(plan, m); diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } - - expected := []string{"foo", "bar"} - if !reflect.DeepEqual(actual, expected) { - t.Fatalf("wrong order\ngot: %#v\nwant: %#v", actual, expected) - } -} - -// Test that destroy ordering is correct with dependencies only -// in the state. -func TestContext2Apply_destroyDependsOnStateOnly(t *testing.T) { - newState := states.NewState() - root := newState.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "foo", - }.Instance(addrs.NoKey), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo"}`), - Dependencies: []addrs.ConfigResource{}, - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("aws"), - Module: addrs.RootModule, - }, - ) - root.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "bar", - }.Instance(addrs.NoKey), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar"}`), - Dependencies: []addrs.ConfigResource{ - { - Resource: addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "foo", - }, - Module: root.Addr.Module(), - }, - }, - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("aws"), - Module: addrs.RootModule, - }, - ) - - // It is possible for this to be racy, so we loop a number of times - // just to check. - for i := 0; i < 10; i++ { - t.Run("new", func(t *testing.T) { - testContext2Apply_destroyDependsOnStateOnly(t, newState) - }) - } -} - -func testContext2Apply_destroyDependsOnStateOnly(t *testing.T, state *states.State) { - state = state.DeepCopy() - m := testModule(t, "empty") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - // Record the order we see Apply - var actual []string - var actualLock sync.Mutex - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse { - actualLock.Lock() - defer actualLock.Unlock() - id := req.PriorState.GetAttr("id").AsString() - actual = append(actual, id) - return testApplyFn(req) - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Parallelism: 1, // To check ordering - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - assertNoErrors(t, diags) - - if _, diags := ctx.Apply(plan, m); diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } - - expected := []string{"bar", "foo"} - if !reflect.DeepEqual(actual, expected) { - t.Fatalf("wrong order\ngot: %#v\nwant: %#v", actual, expected) - } -} - -// Test that destroy ordering is correct with dependencies only -// in the state within a module (GH-11749) -func TestContext2Apply_destroyDependsOnStateOnlyModule(t *testing.T) { - newState := states.NewState() - child := newState.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey)) - child.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "foo", - }.Instance(addrs.NoKey), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo"}`), - Dependencies: []addrs.ConfigResource{}, - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("aws"), - Module: addrs.RootModule, - }, - ) - child.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "bar", - }.Instance(addrs.NoKey), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar"}`), - Dependencies: []addrs.ConfigResource{ - { - Resource: addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "foo", - }, - Module: child.Addr.Module(), - }, - }, - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("aws"), - Module: addrs.RootModule, - }, - ) - - // It is possible for this to be racy, so we loop a number of times - // just to check. - for i := 0; i < 10; i++ { - t.Run("new", func(t *testing.T) { - testContext2Apply_destroyDependsOnStateOnlyModule(t, newState) - }) - } -} - -func testContext2Apply_destroyDependsOnStateOnlyModule(t *testing.T, state *states.State) { - state = state.DeepCopy() - m := testModule(t, "empty") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - // Record the order we see Apply - var actual []string - var actualLock sync.Mutex - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse { - actualLock.Lock() - defer actualLock.Unlock() - id := req.PriorState.GetAttr("id").AsString() - actual = append(actual, id) - return testApplyFn(req) - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Parallelism: 1, // To check ordering - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - assertNoErrors(t, diags) - - if _, diags := ctx.Apply(plan, m); diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } - - expected := []string{"bar", "foo"} - if !reflect.DeepEqual(actual, expected) { - t.Fatalf("wrong order\ngot: %#v\nwant: %#v", actual, expected) - } -} - -func TestContext2Apply_dataBasic(t *testing.T) { - m := testModule(t, "apply-data-basic") - p := testProvider("null") - p.PlanResourceChangeFn = testDiffFn - p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{ - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("yo"), - "foo": cty.NullVal(cty.String), - }), - } - - hook := new(MockHook) - ctx := testContext2(t, &ContextOpts{ - Hooks: []Hook{hook}, - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("null"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } else { - t.Logf(legacyDiffComparisonString(plan.Changes)) - } - - state, diags := ctx.Apply(plan, m) - assertNoErrors(t, diags) - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyDataBasicStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } - - if !hook.PreApplyCalled { - t.Fatal("PreApply not called for data source read") - } - if !hook.PostApplyCalled { - t.Fatal("PostApply not called for data source read") - } -} - -func TestContext2Apply_destroyData(t *testing.T) { - m := testModule(t, "apply-destroy-data-resource") - p := testProvider("null") - p.PlanResourceChangeFn = testDiffFn - p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse { - return providers.ReadDataSourceResponse{ - State: req.Config, - } - } - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("data.null_data_source.testing").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"-"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/null"]`), - ) - - hook := &testHook{} - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("null"): testProviderFuncFixed(p), - }, - Hooks: []Hook{hook}, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } else { - t.Logf(legacyDiffComparisonString(plan.Changes)) - } - - newState, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - if got := len(newState.Modules); got != 1 { - t.Fatalf("state has %d modules after destroy; want 1", got) - } - - if got := len(newState.RootModule().Resources); got != 0 { - t.Fatalf("state has %d resources after destroy; want 0", got) - } - - wantHookCalls := []*testHookCall{ - {"PreApply", "data.null_data_source.testing"}, - {"PostApply", "data.null_data_source.testing"}, - {"PostStateUpdate", ""}, - } - if !reflect.DeepEqual(hook.Calls, wantHookCalls) { - t.Errorf("wrong hook calls\ngot: %swant: %s", spew.Sdump(hook.Calls), spew.Sdump(wantHookCalls)) - } -} - -// https://github.com/hashicorp/terraform/pull/5096 -func TestContext2Apply_destroySkipsCBD(t *testing.T) { - // Config contains CBD resource depending on non-CBD resource, which triggers - // a cycle if they are both replaced, but should _not_ trigger a cycle when - // just doing a `terraform destroy`. - m := testModule(t, "apply-destroy-cbd") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } else { - t.Logf(legacyDiffComparisonString(plan.Changes)) - } - - if _, diags := ctx.Apply(plan, m); diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } -} - -func TestContext2Apply_destroyModuleVarProviderConfig(t *testing.T) { - m := testModule(t, "apply-destroy-mod-var-provider-config") - p := func() (providers.Interface, error) { - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - return p, nil - } - state := states.NewState() - child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey)) - child.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): p, - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - assertNoErrors(t, diags) - - _, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } -} - -func TestContext2Apply_destroyCrossProviders(t *testing.T) { - m := testModule(t, "apply-destroy-cross-providers") - - p_aws := testProvider("aws") - p_aws.ApplyResourceChangeFn = testApplyFn - p_aws.PlanResourceChangeFn = testDiffFn - p_aws.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - }, - }, - "aws_vpc": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - "value": { - Type: cty.String, - Optional: true, - }, - }, - }, - }, - }) - - providers := map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p_aws), - } - - ctx, m, state := getContextForApply_destroyCrossProviders(t, m, providers) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - assertNoErrors(t, diags) - - if _, diags := ctx.Apply(plan, m); diags.HasErrors() { - logDiagnostics(t, diags) - t.Fatal("apply failed") - } -} - -func getContextForApply_destroyCrossProviders(t *testing.T, m *configs.Config, providerFactories map[addrs.Provider]providers.Factory) (*Context, *configs.Config, *states.State) { - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.shared").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"test"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey)) - child.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_vpc.bar").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id": "vpc-aaabbb12", "value":"test"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: providerFactories, - }) - - return ctx, m, state -} - -func TestContext2Apply_minimal(t *testing.T) { - m := testModule(t, "apply-minimal") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyMinimalStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestContext2Apply_cancel(t *testing.T) { - stopped := false - - m := testModule(t, "apply-cancel") - p := testProvider("aws") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse { - if !stopped { - stopped = true - go ctx.Stop() - - for { - if ctx.sh.Stopped() { - break - } - time.Sleep(10 * time.Millisecond) - } - } - return testApplyFn(req) - } - p.PlanResourceChangeFn = testDiffFn - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - // Start the Apply in a goroutine - var applyDiags tfdiags.Diagnostics - stateCh := make(chan *states.State) - go func() { - state, diags := ctx.Apply(plan, m) - applyDiags = diags - - stateCh <- state - }() - - state := <-stateCh - // only expecting an early exit error - if !applyDiags.HasErrors() { - t.Fatal("expected early exit error") - } - - for _, d := range applyDiags { - desc := d.Description() - if desc.Summary != "execution halted" { - t.Fatalf("unexpected error: %v", applyDiags.Err()) - } - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyCancelStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } - - if !p.StopCalled { - t.Fatal("stop should be called") - } -} - -func TestContext2Apply_cancelBlock(t *testing.T) { - m := testModule(t, "apply-cancel-block") - p := testProvider("aws") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - applyCh := make(chan struct{}) - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse { - close(applyCh) - - for !ctx.sh.Stopped() { - // Wait for stop to be called. We call Gosched here so that - // the other goroutines can always be scheduled to set Stopped. - runtime.Gosched() - } - - // Sleep - time.Sleep(100 * time.Millisecond) - return testApplyFn(req) - } - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - // Start the Apply in a goroutine - var applyDiags tfdiags.Diagnostics - stateCh := make(chan *states.State) - go func() { - state, diags := ctx.Apply(plan, m) - applyDiags = diags - - stateCh <- state - }() - - stopDone := make(chan struct{}) - go func() { - defer close(stopDone) - <-applyCh - ctx.Stop() - }() - - // Make sure that stop blocks - select { - case <-stopDone: - t.Fatal("stop should block") - case <-time.After(10 * time.Millisecond): - } - - // Wait for stop - select { - case <-stopDone: - case <-time.After(500 * time.Millisecond): - t.Fatal("stop should be done") - } - - // Wait for apply to complete - state := <-stateCh - // only expecting an early exit error - if !applyDiags.HasErrors() { - t.Fatal("expected early exit error") - } - - for _, d := range applyDiags { - desc := d.Description() - if desc.Summary != "execution halted" { - t.Fatalf("unexpected error: %v", applyDiags.Err()) - } - } - - checkStateString(t, state, ` -aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - num = 2 - type = aws_instance - `) -} - -func TestContext2Apply_cancelProvisioner(t *testing.T) { - m := testModule(t, "apply-cancel-provisioner") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - - pr := testProvisioner() - pr.GetSchemaResponse = provisioners.GetSchemaResponse{ - Provisioner: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": { - Type: cty.String, - Optional: true, - }, - }, - }, - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Provisioners: map[string]provisioners.Factory{ - "shell": testProvisionerFuncFixed(pr), - }, - }) - - prStopped := make(chan struct{}) - pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) { - // Start the stop process - go ctx.Stop() - - <-prStopped - return - } - pr.StopFn = func() error { - close(prStopped) - return nil - } - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - // Start the Apply in a goroutine - var applyDiags tfdiags.Diagnostics - stateCh := make(chan *states.State) - go func() { - state, diags := ctx.Apply(plan, m) - applyDiags = diags - - stateCh <- state - }() - - // Wait for completion - state := <-stateCh - - // we are expecting only an early exit error - if !applyDiags.HasErrors() { - t.Fatal("expected early exit error") - } - - for _, d := range applyDiags { - desc := d.Description() - if desc.Summary != "execution halted" { - t.Fatalf("unexpected error: %v", applyDiags.Err()) - } - } - - checkStateString(t, state, ` -aws_instance.foo: (tainted) - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - num = 2 - type = aws_instance - `) - - if !pr.StopCalled { - t.Fatal("stop should be called") - } -} - -func TestContext2Apply_compute(t *testing.T) { - m := testModule(t, "apply-compute") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "num": { - Type: cty.Number, - Optional: true, - }, - "compute": { - Type: cty.String, - Optional: true, - }, - "compute_value": { - Type: cty.String, - Optional: true, - }, - "foo": { - Type: cty.String, - Optional: true, - }, - "id": { - Type: cty.String, - Computed: true, - }, - "type": { - Type: cty.String, - Computed: true, - }, - "value": { // Populated from compute_value because compute = "value" in the config fixture - Type: cty.String, - Computed: true, - }, - }, - }, - }, - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - SetVariables: InputValues{ - "value": &InputValue{ - Value: cty.NumberIntVal(1), - SourceType: ValueFromCaller, - }, - }, - }) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyComputeStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestContext2Apply_countDecrease(t *testing.T) { - m := testModule(t, "apply-count-dec") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[0]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar","foo": "foo","type": "aws_instance"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[1]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar","foo": "foo","type": "aws_instance"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[2]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar", "foo": "foo", "type": "aws_instance"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - s, diags := ctx.Apply(plan, m) - assertNoErrors(t, diags) - - actual := strings.TrimSpace(s.String()) - expected := strings.TrimSpace(testTerraformApplyCountDecStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestContext2Apply_countDecreaseToOneX(t *testing.T) { - m := testModule(t, "apply-count-dec-one") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[0]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar", "foo": "foo", "type": "aws_instance"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[1]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[2]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - s, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - actual := strings.TrimSpace(s.String()) - expected := strings.TrimSpace(testTerraformApplyCountDecToOneStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -// https://github.com/PeoplePerHour/terraform/pull/11 -// -// This tests a rare but possible situation where we have both a no-key and -// a zero-key instance of the same resource in the configuration when we -// disable count. -// -// The main way to get here is for a provider to fail to destroy the zero-key -// instance but succeed in creating the no-key instance, since those two -// can typically happen concurrently. There are various other ways to get here -// that might be considered user error, such as using "terraform state mv" -// to create a strange combination of different key types on the same resource. -// -// This test indirectly exercises an intentional interaction between -// refactoring.ImpliedMoveStatements and refactoring.ApplyMoves: we'll first -// generate an implied move statement from aws_instance.foo[0] to -// aws_instance.foo, but then refactoring.ApplyMoves should notice that and -// ignore the statement, in the same way as it would if an explicit move -// statement specified the same situation. -func TestContext2Apply_countDecreaseToOneCorrupted(t *testing.T) { - m := testModule(t, "apply-count-dec-one") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar", "foo": "foo", "type": "aws_instance"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[0]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"baz", "type": "aws_instance"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - { - got := strings.TrimSpace(legacyPlanComparisonString(state, plan.Changes)) - want := strings.TrimSpace(testTerraformApplyCountDecToOneCorruptedPlanStr) - if got != want { - t.Fatalf("wrong plan result\ngot:\n%s\nwant:\n%s", got, want) - } - } - { - change := plan.Changes.ResourceInstance(mustResourceInstanceAddr("aws_instance.foo[0]")) - if change == nil { - t.Fatalf("no planned change for instance zero") - } - if got, want := change.Action, plans.Delete; got != want { - t.Errorf("wrong action for instance zero %s; want %s", got, want) - } - if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseWrongRepetition; got != want { - t.Errorf("wrong action reason for instance zero %s; want %s", got, want) - } - } - { - change := plan.Changes.ResourceInstance(mustResourceInstanceAddr("aws_instance.foo")) - if change == nil { - t.Fatalf("no planned change for no-key instance") - } - if got, want := change.Action, plans.NoOp; got != want { - t.Errorf("wrong action for no-key instance %s; want %s", got, want) - } - if got, want := change.ActionReason, plans.ResourceInstanceChangeNoReason; got != want { - t.Errorf("wrong action reason for no-key instance %s; want %s", got, want) - } - } - - s, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - actual := strings.TrimSpace(s.String()) - expected := strings.TrimSpace(testTerraformApplyCountDecToOneCorruptedStr) - if actual != expected { - t.Fatalf("wrong final state\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestContext2Apply_countTainted(t *testing.T) { - m := testModule(t, "apply-count-tainted") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[0]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectTainted, - AttrsJSON: []byte(`{"id":"bar", "type": "aws_instance", "foo": "foo"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - { - got := strings.TrimSpace(legacyDiffComparisonString(plan.Changes)) - want := strings.TrimSpace(` -DESTROY/CREATE: aws_instance.foo[0] - foo: "foo" => "foo" - id: "bar" => "" - type: "aws_instance" => "" -CREATE: aws_instance.foo[1] - foo: "" => "foo" - id: "" => "" - type: "" => "" -`) - if got != want { - t.Fatalf("wrong plan\n\ngot:\n%s\n\nwant:\n%s", got, want) - } - } - - s, diags := ctx.Apply(plan, m) - assertNoErrors(t, diags) - - got := strings.TrimSpace(s.String()) - want := strings.TrimSpace(` -aws_instance.foo.0: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = foo - type = aws_instance -aws_instance.foo.1: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = foo - type = aws_instance -`) - if got != want { - t.Fatalf("wrong final state\n\ngot:\n%s\n\nwant:\n%s", got, want) - } -} - -func TestContext2Apply_countVariable(t *testing.T) { - m := testModule(t, "apply-count-variable") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyCountVariableStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestContext2Apply_countVariableRef(t *testing.T) { - m := testModule(t, "apply-count-variable-ref") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyCountVariableRefStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestContext2Apply_provisionerInterpCount(t *testing.T) { - // This test ensures that a provisioner can interpolate a resource count - // even though the provisioner expression is evaluated during the plan - // walk. https://github.com/hashicorp/terraform/issues/16840 - - m, snap := testModuleWithSnapshot(t, "apply-provisioner-interp-count") - - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - pr := testProvisioner() - - Providers := map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - } - - provisioners := map[string]provisioners.Factory{ - "local-exec": testProvisionerFuncFixed(pr), - } - ctx := testContext2(t, &ContextOpts{ - Providers: Providers, - Provisioners: provisioners, - }) - - plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))) - assertNoErrors(t, diags) - - // We'll marshal and unmarshal the plan here, to ensure that we have - // a clean new context as would be created if we separately ran - // terraform plan -out=tfplan && terraform apply tfplan - ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan) - if err != nil { - t.Fatal(err) - } - ctxOpts.Providers = Providers - ctxOpts.Provisioners = provisioners - ctx, diags = NewContext(ctxOpts) - if diags.HasErrors() { - t.Fatalf("failed to create context for plan: %s", diags.Err()) - } - - // Applying the plan should now succeed - _, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("apply failed unexpectedly: %s", diags.Err()) - } - - // Verify apply was invoked - if !pr.ProvisionResourceCalled { - t.Fatalf("provisioner was not called") - } -} - -func TestContext2Apply_foreachVariable(t *testing.T) { - m := testModule(t, "plan-for-each-unknown-value") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "foo": &InputValue{ - Value: cty.StringVal("hello"), - }, - }, - }) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyForEachVariableStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestContext2Apply_moduleBasic(t *testing.T) { - m := testModule(t, "apply-module") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyModuleStr) - if actual != expected { - t.Fatalf("bad, expected:\n%s\n\nactual:\n%s", expected, actual) - } -} - -func TestContext2Apply_moduleDestroyOrder(t *testing.T) { - m := testModule(t, "apply-module-destroy-order") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - // Create a custom apply function to track the order they were destroyed - var order []string - var orderLock sync.Mutex - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - id := req.PriorState.GetAttr("id").AsString() - - if id == "b" { - // Pause briefly to make any race conditions more visible, since - // missing edges here can cause undeterministic ordering. - time.Sleep(100 * time.Millisecond) - } - - orderLock.Lock() - defer orderLock.Unlock() - - order = append(order, id) - resp.NewState = req.PlannedState - return resp - } - - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Required: true}, - "blah": {Type: cty.String, Optional: true}, - "value": {Type: cty.String, Optional: true}, - }, - }, - }, - }) - - state := states.NewState() - child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey)) - child.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.a").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"a"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.b").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"b"}`), - Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("module.child.aws_instance.a")}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - assertNoErrors(t, diags) - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - expected := []string{"b", "a"} - if !reflect.DeepEqual(order, expected) { - t.Errorf("wrong order\ngot: %#v\nwant: %#v", order, expected) - } - - { - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyModuleDestroyOrderStr) - if actual != expected { - t.Errorf("wrong final state\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } - } -} - -func TestContext2Apply_moduleInheritAlias(t *testing.T) { - m := testModule(t, "apply-module-provider-inherit-alias") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - - p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) { - val := req.Config.GetAttr("value") - if val.IsNull() { - return - } - - root := req.Config.GetAttr("root") - if !root.IsNull() { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("child should not get root")) - } - - return - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - checkStateString(t, state, ` - -module.child: - aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"].eu - type = aws_instance - `) -} - -func TestContext2Apply_orphanResource(t *testing.T) { - // This is a two-step test: - // 1. Apply a configuration with resources that have count set. - // This should place the empty resource object in the state to record - // that each exists, and record any instances. - // 2. Apply an empty configuration against the same state, which should - // then clean up both the instances and the containing resource objects. - p := testProvider("test") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test_thing": { - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Computed: true}, - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - }) - - // Step 1: create the resources and instances - m := testModule(t, "apply-orphan-resource") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - state, diags := ctx.Apply(plan, m) - assertNoErrors(t, diags) - - // At this point both resources should be recorded in the state, along - // with the single instance associated with test_thing.one. - want := states.BuildState(func(s *states.SyncState) { - providerAddr := addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("test"), - Module: addrs.RootModule, - } - oneAddr := addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_thing", - Name: "one", - }.Absolute(addrs.RootModuleInstance) - s.SetResourceProvider(oneAddr, providerAddr) - s.SetResourceInstanceCurrent(oneAddr.Instance(addrs.IntKey(0)), &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo"}`), - }, providerAddr) - }) - - if state.String() != want.String() { - t.Fatalf("wrong state after step 1\n%s", cmp.Diff(want, state)) - } - - // Step 2: update with an empty config, to destroy everything - m = testModule(t, "empty") - ctx = testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - plan, diags = ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - { - addr := mustResourceInstanceAddr("test_thing.one[0]") - change := plan.Changes.ResourceInstance(addr) - if change == nil { - t.Fatalf("no planned change for %s", addr) - } - if got, want := change.Action, plans.Delete; got != want { - t.Errorf("wrong action for %s %s; want %s", addr, got, want) - } - if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseNoResourceConfig; got != want { - t.Errorf("wrong action for %s %s; want %s", addr, got, want) - } - } - - state, diags = ctx.Apply(plan, m) - assertNoErrors(t, diags) - - // The state should now be _totally_ empty, with just an empty root module - // (since that always exists) and no resources at all. - want = states.NewState() - want.CheckResults = &states.CheckResults{} - if !cmp.Equal(state, want) { - t.Fatalf("wrong state after step 2\ngot: %swant: %s", spew.Sdump(state), spew.Sdump(want)) - } - -} - -func TestContext2Apply_moduleOrphanInheritAlias(t *testing.T) { - m := testModule(t, "apply-module-provider-inherit-alias-orphan") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) { - val := req.Config.GetAttr("value") - if val.IsNull() { - return - } - - root := req.Config.GetAttr("root") - if !root.IsNull() { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("child should not get root")) - } - - return - } - - // Create a state with an orphan module - state := states.NewState() - child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey)) - child.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - { - addr := mustResourceInstanceAddr("module.child.aws_instance.bar") - change := plan.Changes.ResourceInstance(addr) - if change == nil { - t.Fatalf("no planned change for %s", addr) - } - if got, want := change.Action, plans.Delete; got != want { - t.Errorf("wrong action for %s %s; want %s", addr, got, want) - } - // This should ideally be ResourceInstanceDeleteBecauseNoModule, but - // the codepath deciding this doesn't currently have enough information - // to differentiate, and so this is a compromise. - if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseNoResourceConfig; got != want { - t.Errorf("wrong action for %s %s; want %s", addr, got, want) - } - } - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - if !p.ConfigureProviderCalled { - t.Fatal("must call configure") - } - - checkStateString(t, state, "") -} - -func TestContext2Apply_moduleOrphanProvider(t *testing.T) { - m := testModule(t, "apply-module-orphan-provider-inherit") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) { - val := req.Config.GetAttr("value") - if val.IsNull() { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("value is not found")) - } - - return - } - - // Create a state with an orphan module - state := states.NewState() - child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey)) - child.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - if _, diags := ctx.Apply(plan, m); diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } -} - -func TestContext2Apply_moduleOrphanGrandchildProvider(t *testing.T) { - m := testModule(t, "apply-module-orphan-provider-inherit") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) { - val := req.Config.GetAttr("value") - if val.IsNull() { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("value is not found")) - } - - return - } - - // Create a state with an orphan module that is nested (grandchild) - state := states.NewState() - child := state.EnsureModule(addrs.RootModuleInstance.Child("parent", addrs.NoKey).Child("child", addrs.NoKey)) - child.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - if _, diags := ctx.Apply(plan, m); diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } -} - -func TestContext2Apply_moduleGrandchildProvider(t *testing.T) { - m := testModule(t, "apply-module-grandchild-provider-inherit") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - var callLock sync.Mutex - called := false - p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) { - val := req.Config.GetAttr("value") - if val.IsNull() { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("value is not found")) - } - - callLock.Lock() - called = true - callLock.Unlock() - - return - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - if _, diags := ctx.Apply(plan, m); diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } - - callLock.Lock() - defer callLock.Unlock() - if called != true { - t.Fatalf("err: configure never called") - } -} - -// This tests an issue where all the providers in a module but not -// in the root weren't being added to the root properly. In this test -// case: aws is explicitly added to root, but "test" should be added to. -// With the bug, it wasn't. -func TestContext2Apply_moduleOnlyProvider(t *testing.T) { - m := testModule(t, "apply-module-only-provider") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - pTest := testProvider("test") - pTest.ApplyResourceChangeFn = testApplyFn - pTest.PlanResourceChangeFn = testDiffFn - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - addrs.NewDefaultProvider("test"): testProviderFuncFixed(pTest), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyModuleOnlyProviderStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestContext2Apply_moduleProviderAlias(t *testing.T) { - m := testModule(t, "apply-module-provider-alias") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyModuleProviderAliasStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestContext2Apply_moduleProviderAliasTargets(t *testing.T) { - m := testModule(t, "apply-module-provider-alias") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - Targets: []addrs.Targetable{ - addrs.ConfigResource{ - Module: addrs.RootModule, - Resource: addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "nonexistent", - Name: "thing", - }, - }, - }, - }) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(` - - `) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestContext2Apply_moduleProviderCloseNested(t *testing.T) { - m := testModule(t, "apply-module-provider-close-nested") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - assertNoErrors(t, diags) - - if _, diags := ctx.Apply(plan, m); diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } -} - -// Tests that variables used as module vars that reference data that -// already exists in the state and requires no diff works properly. This -// fixes an issue faced where module variables were pruned because they were -// accessing "non-existent" resources (they existed, just not in the graph -// cause they weren't in the diff). -func TestContext2Apply_moduleVarRefExisting(t *testing.T) { - m := testModule(t, "apply-ref-existing") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo","foo":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyModuleVarRefExistingStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestContext2Apply_moduleVarResourceCount(t *testing.T) { - m := testModule(t, "apply-module-var-resource-count") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.DestroyMode, - SetVariables: InputValues{ - "num": &InputValue{ - Value: cty.NumberIntVal(2), - SourceType: ValueFromCaller, - }, - }, - }) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - assertNoErrors(t, diags) - - ctx = testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags = ctx.Plan(m, state, &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "num": &InputValue{ - Value: cty.NumberIntVal(5), - SourceType: ValueFromCaller, - }, - }, - }) - assertNoErrors(t, diags) - - if _, diags := ctx.Apply(plan, m); diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } -} - -// GH-819 -func TestContext2Apply_moduleBool(t *testing.T) { - m := testModule(t, "apply-module-bool") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyModuleBoolStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -// Tests that a module can be targeted and everything is properly created. -// This adds to the plan test to also just verify that apply works. -func TestContext2Apply_moduleTarget(t *testing.T) { - m := testModule(t, "plan-targeted-cross-module") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - Targets: []addrs.Targetable{ - addrs.RootModuleInstance.Child("B", addrs.NoKey), - }, - }) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - checkStateString(t, state, ` - -module.A: - aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = bar - type = aws_instance - - Outputs: - - value = foo -module.B: - aws_instance.bar: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = foo - type = aws_instance - - Dependencies: - module.A.aws_instance.foo - `) -} - -func TestContext2Apply_multiProvider(t *testing.T) { - m := testModule(t, "apply-multi-provider") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - - pDO := testProvider("do") - pDO.ApplyResourceChangeFn = testApplyFn - pDO.PlanResourceChangeFn = testDiffFn - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - addrs.NewDefaultProvider("do"): testProviderFuncFixed(pDO), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - mod := state.RootModule() - if len(mod.Resources) < 2 { - t.Fatalf("bad: %#v", mod.Resources) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyMultiProviderStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestContext2Apply_multiProviderDestroy(t *testing.T) { - m := testModule(t, "apply-multi-provider-destroy") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - Provider: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "addr": {Type: cty.String, Optional: true}, - }, - }, - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Computed: true}, - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - }) - - p2 := testProvider("vault") - p2.ApplyResourceChangeFn = testApplyFn - p2.PlanResourceChangeFn = testDiffFn - p2.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "vault_instance": { - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Computed: true}, - }, - }, - }, - }) - - var state *states.State - - // First, create the instances - { - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - addrs.NewDefaultProvider("vault"): testProviderFuncFixed(p2), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - s, diags := ctx.Apply(plan, m) - assertNoErrors(t, diags) - - state = s - } - - // Destroy them - { - // Verify that aws_instance.bar is destroyed first - var checked bool - var called int32 - var lock sync.Mutex - applyFn := func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - lock.Lock() - defer lock.Unlock() - - if req.TypeName == "aws_instance" { - checked = true - - // Sleep to allow parallel execution - time.Sleep(50 * time.Millisecond) - - // Verify that called is 0 (dep not called) - if atomic.LoadInt32(&called) != 0 { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("nothing else should be called")) - return resp - } - } - - atomic.AddInt32(&called, 1) - return testApplyFn(req) - } - - // Set the apply functions - p.ApplyResourceChangeFn = applyFn - p2.ApplyResourceChangeFn = applyFn - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - addrs.NewDefaultProvider("vault"): testProviderFuncFixed(p2), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - assertNoErrors(t, diags) - - s, diags := ctx.Apply(plan, m) - assertNoErrors(t, diags) - - if !checked { - t.Fatal("should be checked") - } - - state = s - } - - checkStateString(t, state, ``) -} - -// This is like the multiProviderDestroy test except it tests that -// dependent resources within a child module that inherit provider -// configuration are still destroyed first. -func TestContext2Apply_multiProviderDestroyChild(t *testing.T) { - m := testModule(t, "apply-multi-provider-destroy-child") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - Provider: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "value": {Type: cty.String, Optional: true}, - }, - }, - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Computed: true}, - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - }) - - p2 := testProvider("vault") - p2.ApplyResourceChangeFn = testApplyFn - p2.PlanResourceChangeFn = testDiffFn - p2.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - Provider: &configschema.Block{}, - ResourceTypes: map[string]*configschema.Block{ - "vault_instance": { - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Computed: true}, - }, - }, - }, - }) - - var state *states.State - - // First, create the instances - { - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - addrs.NewDefaultProvider("vault"): testProviderFuncFixed(p2), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - s, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - state = s - } - - // Destroy them - { - // Verify that aws_instance.bar is destroyed first - var checked bool - var called int32 - var lock sync.Mutex - applyFn := func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - lock.Lock() - defer lock.Unlock() - - if req.TypeName == "aws_instance" { - checked = true - - // Sleep to allow parallel execution - time.Sleep(50 * time.Millisecond) - - // Verify that called is 0 (dep not called) - if atomic.LoadInt32(&called) != 0 { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("nothing else should be called")) - return resp - } - } - - atomic.AddInt32(&called, 1) - return testApplyFn(req) - } - - // Set the apply functions - p.ApplyResourceChangeFn = applyFn - p2.ApplyResourceChangeFn = applyFn - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - addrs.NewDefaultProvider("vault"): testProviderFuncFixed(p2), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - assertNoErrors(t, diags) - - s, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - if !checked { - t.Fatal("should be checked") - } - - state = s - } - - checkStateString(t, state, ` - -`) -} - -func TestContext2Apply_multiVar(t *testing.T) { - m := testModule(t, "apply-multi-var") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - // First, apply with a count of 3 - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "num": &InputValue{ - Value: cty.NumberIntVal(3), - SourceType: ValueFromCaller, - }, - }, - }) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - actual := state.RootModule().OutputValues["output"] - expected := cty.StringVal("bar0,bar1,bar2") - if actual == nil || actual.Value != expected { - t.Fatalf("wrong value\ngot: %#v\nwant: %#v", actual.Value, expected) - } - - t.Logf("Initial state: %s", state.String()) - - // Apply again, reduce the count to 1 - { - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "num": &InputValue{ - Value: cty.NumberIntVal(1), - SourceType: ValueFromCaller, - }, - }, - }) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - t.Logf("End state: %s", state.String()) - - actual := state.RootModule().OutputValues["output"] - if actual == nil { - t.Fatal("missing output") - } - - expected := cty.StringVal("bar0") - if actual.Value != expected { - t.Fatalf("wrong value\ngot: %#v\nwant: %#v", actual.Value, expected) - } - } -} - -// This is a holistic test of multi-var (aka "splat variable") handling -// across several different Terraform subsystems. This is here because -// historically there were quirky differences in handling across different -// parts of Terraform and so here we want to assert the expected behavior and -// ensure that it remains consistent in future. -func TestContext2Apply_multiVarComprehensive(t *testing.T) { - m := testModule(t, "apply-multi-var-comprehensive") - p := testProvider("test") - - configs := map[string]cty.Value{} - var configsLock sync.Mutex - - p.ApplyResourceChangeFn = testApplyFn - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse { - proposed := req.ProposedNewState - configsLock.Lock() - defer configsLock.Unlock() - key := proposed.GetAttr("key").AsString() - // This test was originally written using the legacy p.PlanResourceChangeFn interface, - // and so the assertions below expect an old-style ResourceConfig, which - // we'll construct via our shim for now to avoid rewriting all of the - // assertions. - configs[key] = req.ProposedNewState - - retVals := make(map[string]cty.Value) - for it := proposed.ElementIterator(); it.Next(); { - idxVal, val := it.Element() - idx := idxVal.AsString() - - switch idx { - case "id": - retVals[idx] = cty.UnknownVal(cty.String) - case "name": - retVals[idx] = cty.StringVal(key) - default: - retVals[idx] = val - } - } - - return providers.PlanResourceChangeResponse{ - PlannedState: cty.ObjectVal(retVals), - } - } - - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test_thing": { - Attributes: map[string]*configschema.Attribute{ - "key": {Type: cty.String, Required: true}, - - "source_id": {Type: cty.String, Optional: true}, - "source_name": {Type: cty.String, Optional: true}, - "first_source_id": {Type: cty.String, Optional: true}, - "first_source_name": {Type: cty.String, Optional: true}, - "source_ids": {Type: cty.List(cty.String), Optional: true}, - "source_names": {Type: cty.List(cty.String), Optional: true}, - "source_ids_from_func": {Type: cty.List(cty.String), Optional: true}, - "source_names_from_func": {Type: cty.List(cty.String), Optional: true}, - "source_ids_wrapped": {Type: cty.List(cty.List(cty.String)), Optional: true}, - "source_names_wrapped": {Type: cty.List(cty.List(cty.String)), Optional: true}, - - "id": {Type: cty.String, Computed: true}, - "name": {Type: cty.String, Computed: true}, - }, - }, - }, - }) - - // First, apply with a count of 3 - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "num": &InputValue{ - Value: cty.NumberIntVal(3), - SourceType: ValueFromCaller, - }, - }, - }) - assertNoErrors(t, diags) - - checkConfig := func(key string, want cty.Value) { - configsLock.Lock() - defer configsLock.Unlock() - - got, ok := configs[key] - if !ok { - t.Errorf("no config recorded for %s; expected a configuration", key) - return - } - - t.Run("config for "+key, func(t *testing.T) { - for _, problem := range deep.Equal(got, want) { - t.Errorf(problem) - } - }) - } - - checkConfig("multi_count_var.0", cty.ObjectVal(map[string]cty.Value{ - "source_id": cty.UnknownVal(cty.String), - "source_name": cty.StringVal("source.0"), - })) - checkConfig("multi_count_var.2", cty.ObjectVal(map[string]cty.Value{ - "source_id": cty.UnknownVal(cty.String), - "source_name": cty.StringVal("source.2"), - })) - checkConfig("multi_count_derived.0", cty.ObjectVal(map[string]cty.Value{ - "source_id": cty.UnknownVal(cty.String), - "source_name": cty.StringVal("source.0"), - })) - checkConfig("multi_count_derived.2", cty.ObjectVal(map[string]cty.Value{ - "source_id": cty.UnknownVal(cty.String), - "source_name": cty.StringVal("source.2"), - })) - checkConfig("whole_splat", cty.ObjectVal(map[string]cty.Value{ - "source_ids": cty.ListVal([]cty.Value{ - cty.UnknownVal(cty.String), - cty.UnknownVal(cty.String), - cty.UnknownVal(cty.String), - }), - "source_names": cty.ListVal([]cty.Value{ - cty.StringVal("source.0"), - cty.StringVal("source.1"), - cty.StringVal("source.2"), - }), - "source_ids_from_func": cty.UnknownVal(cty.String), - "source_names_from_func": cty.ListVal([]cty.Value{ - cty.StringVal("source.0"), - cty.StringVal("source.1"), - cty.StringVal("source.2"), - }), - "source_ids_wrapped": cty.ListVal([]cty.Value{ - cty.ListVal([]cty.Value{ - cty.UnknownVal(cty.String), - cty.UnknownVal(cty.String), - cty.UnknownVal(cty.String), - }), - }), - "source_names_wrapped": cty.ListVal([]cty.Value{ - cty.ListVal([]cty.Value{ - cty.StringVal("source.0"), - cty.StringVal("source.1"), - cty.StringVal("source.2"), - }), - }), - "first_source_id": cty.UnknownVal(cty.String), - "first_source_name": cty.StringVal("source.0"), - })) - checkConfig("child.whole_splat", cty.ObjectVal(map[string]cty.Value{ - "source_ids": cty.ListVal([]cty.Value{ - cty.UnknownVal(cty.String), - cty.UnknownVal(cty.String), - cty.UnknownVal(cty.String), - }), - "source_names": cty.ListVal([]cty.Value{ - cty.StringVal("source.0"), - cty.StringVal("source.1"), - cty.StringVal("source.2"), - }), - "source_ids_wrapped": cty.ListVal([]cty.Value{ - cty.ListVal([]cty.Value{ - cty.UnknownVal(cty.String), - cty.UnknownVal(cty.String), - cty.UnknownVal(cty.String), - }), - }), - "source_names_wrapped": cty.ListVal([]cty.Value{ - cty.ListVal([]cty.Value{ - cty.StringVal("source.0"), - cty.StringVal("source.1"), - cty.StringVal("source.2"), - }), - }), - })) - - t.Run("apply", func(t *testing.T) { - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("error during apply: %s", diags.Err()) - } - - want := map[string]interface{}{ - "source_ids": []interface{}{"foo", "foo", "foo"}, - "source_names": []interface{}{ - "source.0", - "source.1", - "source.2", - }, - } - got := map[string]interface{}{} - for k, s := range state.RootModule().OutputValues { - got[k] = hcl2shim.ConfigValueFromHCL2(s.Value) - } - if !reflect.DeepEqual(got, want) { - t.Errorf( - "wrong outputs\ngot: %s\nwant: %s", - spew.Sdump(got), spew.Sdump(want), - ) - } - }) -} - -// Test that multi-var (splat) access is ordered by count, not by -// value. -func TestContext2Apply_multiVarOrder(t *testing.T) { - m := testModule(t, "apply-multi-var-order") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - // First, apply with a count of 3 - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - t.Logf("State: %s", state.String()) - - actual := state.RootModule().OutputValues["should-be-11"] - expected := cty.StringVal("index-11") - if actual == nil || actual.Value != expected { - t.Fatalf("wrong value\ngot: %#v\nwant: %#v", actual.Value, expected) - } -} - -// Test that multi-var (splat) access is ordered by count, not by -// value, through interpolations. -func TestContext2Apply_multiVarOrderInterp(t *testing.T) { - m := testModule(t, "apply-multi-var-order-interp") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - // First, apply with a count of 3 - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - t.Logf("State: %s", state.String()) - - actual := state.RootModule().OutputValues["should-be-11"] - expected := cty.StringVal("baz-index-11") - if actual == nil || actual.Value != expected { - t.Fatalf("wrong value\ngot: %#v\nwant: %#v", actual.Value, expected) - } -} - -// Based on GH-10440 where a graph edge wasn't properly being created -// between a modified resource and a count instance being destroyed. -func TestContext2Apply_multiVarCountDec(t *testing.T) { - var s *states.State - - // First create resources. Nothing sneaky here. - { - m := testModule(t, "apply-multi-var-count-dec") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - log.Print("\n========\nStep 1 Plan\n========") - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "num": &InputValue{ - Value: cty.NumberIntVal(2), - SourceType: ValueFromCaller, - }, - }, - }) - assertNoErrors(t, diags) - - log.Print("\n========\nStep 1 Apply\n========") - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - t.Logf("Step 1 state:\n%s", state) - - s = state - } - - // Decrease the count by 1 and verify that everything happens in the - // right order. - m := testModule(t, "apply-multi-var-count-dec") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - // Verify that aws_instance.bar is modified first and nothing - // else happens at the same time. - { - var checked bool - var called int32 - var lock sync.Mutex - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - lock.Lock() - defer lock.Unlock() - - if !req.PlannedState.IsNull() { - s := req.PlannedState.AsValueMap() - if ami, ok := s["ami"]; ok && !ami.IsNull() && ami.AsString() == "special" { - checked = true - - // Sleep to allow parallel execution - time.Sleep(50 * time.Millisecond) - - // Verify that called is 0 (dep not called) - if atomic.LoadInt32(&called) != 1 { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("nothing else should be called")) - return - } - } - } - atomic.AddInt32(&called, 1) - return testApplyFn(req) - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - log.Print("\n========\nStep 2 Plan\n========") - plan, diags := ctx.Plan(m, s, &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "num": &InputValue{ - Value: cty.NumberIntVal(1), - SourceType: ValueFromCaller, - }, - }, - }) - assertNoErrors(t, diags) - - t.Logf("Step 2 plan:\n%s", legacyDiffComparisonString(plan.Changes)) - - log.Print("\n========\nStep 2 Apply\n========") - _, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } - - if !checked { - t.Error("apply never called") - } - } -} - -// Test that we can resolve a multi-var (splat) for the first resource -// created in a non-root module, which happens when the module state doesn't -// exist yet. -// https://github.com/hashicorp/terraform/issues/14438 -func TestContext2Apply_multiVarMissingState(t *testing.T) { - m := testModule(t, "apply-multi-var-missing-state") - p := testProvider("test") - p.PlanResourceChangeFn = testDiffFn - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test_thing": { - Attributes: map[string]*configschema.Attribute{ - "a_ids": {Type: cty.String, Optional: true}, - "id": {Type: cty.String, Computed: true}, - }, - }, - }, - }) - - // First, apply with a count of 3 - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - // Before the relevant bug was fixed, Terraform would panic during apply. - if _, diags := ctx.Apply(plan, m); diags.HasErrors() { - t.Fatalf("apply failed: %s", diags.Err()) - } - - // If we get here with no errors or panics then our test was successful. -} - -func TestContext2Apply_outputOrphan(t *testing.T) { - m := testModule(t, "apply-output-orphan") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetOutputValue("foo", cty.StringVal("bar"), false) - root.SetOutputValue("bar", cty.StringVal("baz"), false) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyOutputOrphanStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestContext2Apply_outputOrphanModule(t *testing.T) { - m := testModule(t, "apply-output-orphan-module") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - state := states.NewState() - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - s, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - actual := strings.TrimSpace(s.String()) - expected := strings.TrimSpace(testTerraformApplyOutputOrphanModuleStr) - if actual != expected { - t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) - } - - // now apply with no module in the config, which should remove the - // remaining output - ctx = testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - emptyConfig := configs.NewEmptyConfig() - - // NOTE: While updating this test to pass the state in as a Plan argument, - // rather than into the testContext2 call above, it previously said - // State: state.DeepCopy(), which is a little weird since we just - // created "s" above as the result of the previous apply, but I've preserved - // it to avoid changing the flow of this test in case that's important - // for some reason. - plan, diags = ctx.Plan(emptyConfig, state.DeepCopy(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags = ctx.Apply(plan, emptyConfig) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - if !state.Empty() { - t.Fatalf("wrong final state %s\nwant empty state", spew.Sdump(state)) - } -} - -func TestContext2Apply_providerComputedVar(t *testing.T) { - m := testModule(t, "apply-provider-computed") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - pTest := testProvider("test") - pTest.ApplyResourceChangeFn = testApplyFn - pTest.PlanResourceChangeFn = testDiffFn - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - addrs.NewDefaultProvider("test"): testProviderFuncFixed(pTest), - }, - }) - - p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) { - val := req.Config.GetAttr("value") - if val.IsNull() { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("value is not found")) - return - } - return - } - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - if _, diags := ctx.Apply(plan, m); diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } -} - -func TestContext2Apply_providerConfigureDisabled(t *testing.T) { - m := testModule(t, "apply-provider-configure-disabled") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) { - val := req.Config.GetAttr("value") - if val.IsNull() { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("value is not found")) - } - - return - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - if _, diags := ctx.Apply(plan, m); diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } - - if !p.ConfigureProviderCalled { - t.Fatal("configure never called") - } -} - -func TestContext2Apply_provisionerModule(t *testing.T) { - m := testModule(t, "apply-provisioner-module") - - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - - pr := testProvisioner() - pr.GetSchemaResponse = provisioners.GetSchemaResponse{ - Provisioner: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Provisioners: map[string]provisioners.Factory{ - "shell": testProvisionerFuncFixed(pr), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyProvisionerModuleStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } - - // Verify apply was invoked - if !pr.ProvisionResourceCalled { - t.Fatalf("provisioner not invoked") - } -} - -func TestContext2Apply_Provisioner_compute(t *testing.T) { - m := testModule(t, "apply-provisioner-compute") - p := testProvider("aws") - pr := testProvisioner() - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) { - - val := req.Config.GetAttr("command").AsString() - if val != "computed_value" { - t.Fatalf("bad value for foo: %q", val) - } - req.UIOutput.Output(fmt.Sprintf("Executing: %q", val)) - - return - } - h := new(MockHook) - ctx := testContext2(t, &ContextOpts{ - Hooks: []Hook{h}, - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Provisioners: map[string]provisioners.Factory{ - "shell": testProvisionerFuncFixed(pr), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "value": &InputValue{ - Value: cty.NumberIntVal(1), - SourceType: ValueFromCaller, - }, - }, - }) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyProvisionerStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } - - // Verify apply was invoked - if !pr.ProvisionResourceCalled { - t.Fatalf("provisioner not invoked") - } - - // Verify output was rendered - if !h.ProvisionOutputCalled { - t.Fatalf("ProvisionOutput hook not called") - } - if got, want := h.ProvisionOutputMessage, `Executing: "computed_value"`; got != want { - t.Errorf("expected output to be %q, but was %q", want, got) - } -} - -func TestContext2Apply_provisionerCreateFail(t *testing.T) { - m := testModule(t, "apply-provisioner-fail-create") - p := testProvider("aws") - pr := testProvisioner() - p.PlanResourceChangeFn = testDiffFn - - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse { - resp := testApplyFn(req) - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("error")) - - return resp - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Provisioners: map[string]provisioners.Factory{ - "shell": testProvisionerFuncFixed(pr), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags == nil { - t.Fatal("should error") - } - - got := strings.TrimSpace(state.String()) - want := strings.TrimSpace(testTerraformApplyProvisionerFailCreateStr) - if got != want { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", got, want) - } -} - -func TestContext2Apply_provisionerCreateFailNoId(t *testing.T) { - m := testModule(t, "apply-provisioner-fail-create") - p := testProvider("aws") - pr := testProvisioner() - p.PlanResourceChangeFn = testDiffFn - - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("error")) - return - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Provisioners: map[string]provisioners.Factory{ - "shell": testProvisionerFuncFixed(pr), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags == nil { - t.Fatal("should error") - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyProvisionerFailCreateNoIdStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestContext2Apply_provisionerFail(t *testing.T) { - m := testModule(t, "apply-provisioner-fail") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - pr := testProvisioner() - pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("EXPLOSION")) - return - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Provisioners: map[string]provisioners.Factory{ - "shell": testProvisionerFuncFixed(pr), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags == nil { - t.Fatal("should error") - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyProvisionerFailStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestContext2Apply_provisionerFail_createBeforeDestroy(t *testing.T) { - m := testModule(t, "apply-provisioner-fail-create-before") - p := testProvider("aws") - pr := testProvisioner() - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("EXPLOSION")) - return - } - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar","require_new":"abc"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Provisioners: map[string]provisioners.Factory{ - "shell": testProvisionerFuncFixed(pr), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags = ctx.Apply(plan, m) - if !diags.HasErrors() { - t.Fatal("should error") - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyProvisionerFailCreateBeforeDestroyStr) - if actual != expected { - t.Fatalf("expected:\n%s\n:got\n%s", expected, actual) - } -} - -func TestContext2Apply_error_createBeforeDestroy(t *testing.T) { - m := testModule(t, "apply-error-create-before") - p := testProvider("aws") - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar", "require_new": "abc","type":"aws_instance"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("placeholder error from ApplyFn")) - return - } - p.PlanResourceChangeFn = testDiffFn - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags = ctx.Apply(plan, m) - if !diags.HasErrors() { - t.Fatal("should have error") - } - if got, want := diags.Err().Error(), "placeholder error from ApplyFn"; got != want { - // We're looking for our artificial error from ApplyFn above, whose - // message is literally "placeholder error from ApplyFn". - t.Fatalf("wrong error\ngot: %s\nwant: %s", got, want) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyErrorCreateBeforeDestroyStr) - if actual != expected { - t.Fatalf("wrong final state\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestContext2Apply_errorDestroy_createBeforeDestroy(t *testing.T) { - m := testModule(t, "apply-error-create-before") - p := testProvider("aws") - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar", "require_new": "abc"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - // Fail the destroy! - if req.PlannedState.IsNull() { - resp.NewState = req.PriorState - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("error")) - return - } - - return testApplyFn(req) - } - p.PlanResourceChangeFn = testDiffFn - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags = ctx.Apply(plan, m) - if !diags.HasErrors() { - t.Fatal("should have error") - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyErrorDestroyCreateBeforeDestroyStr) - if actual != expected { - t.Fatalf("bad: actual:\n%s\n\nexpected:\n%s", actual, expected) - } -} - -func TestContext2Apply_multiDepose_createBeforeDestroy(t *testing.T) { - m := testModule(t, "apply-multi-depose-create-before-destroy") - p := testProvider("aws") - ps := map[addrs.Provider]providers.Factory{addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p)} - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "require_new": {Type: cty.String, Optional: true}, - "id": {Type: cty.String, Computed: true}, - }, - }, - }, - }) - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.web").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - p.PlanResourceChangeFn = testDiffFn - - ctx := testContext2(t, &ContextOpts{ - Providers: ps, - }) - createdInstanceId := "bar" - // Create works - createFunc := func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - s := req.PlannedState.AsValueMap() - s["id"] = cty.StringVal(createdInstanceId) - resp.NewState = cty.ObjectVal(s) - return - } - - // Destroy starts broken - destroyFunc := func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - resp.NewState = req.PriorState - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("destroy failed")) - return - } - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - if req.PlannedState.IsNull() { - return destroyFunc(req) - } else { - return createFunc(req) - } - } - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "require_new": &InputValue{ - Value: cty.StringVal("yes"), - }, - }, - }) - assertNoErrors(t, diags) - - // Destroy is broken, so even though CBD successfully replaces the instance, - // we'll have to save the Deposed instance to destroy later - state, diags = ctx.Apply(plan, m) - if !diags.HasErrors() { - t.Fatal("should have error") - } - - checkStateString(t, state, ` -aws_instance.web: (1 deposed) - ID = bar - provider = provider["registry.terraform.io/hashicorp/aws"] - require_new = yes - Deposed ID 1 = foo - `) - - createdInstanceId = "baz" - ctx = testContext2(t, &ContextOpts{ - Providers: ps, - }) - - plan, diags = ctx.Plan(m, state, &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "require_new": &InputValue{ - Value: cty.StringVal("baz"), - }, - }, - }) - assertNoErrors(t, diags) - - // We're replacing the primary instance once again. Destroy is _still_ - // broken, so the Deposed list gets longer - state, diags = ctx.Apply(plan, m) - if !diags.HasErrors() { - t.Fatal("should have error") - } - - // For this one we can't rely on checkStateString because its result is - // not deterministic when multiple deposed objects are present. Instead, - // we will probe the state object directly. - { - is := state.RootModule().Resources["aws_instance.web"].Instances[addrs.NoKey] - if is.Current == nil { - t.Fatalf("no current object for aws_instance web; should have one") - } - if !bytes.Contains(is.Current.AttrsJSON, []byte("baz")) { - t.Fatalf("incorrect current object attrs %s; want id=baz", is.Current.AttrsJSON) - } - if got, want := len(is.Deposed), 2; got != want { - t.Fatalf("wrong number of deposed instances %d; want %d", got, want) - } - var foos, bars int - for _, obj := range is.Deposed { - if bytes.Contains(obj.AttrsJSON, []byte("foo")) { - foos++ - } - if bytes.Contains(obj.AttrsJSON, []byte("bar")) { - bars++ - } - } - if got, want := foos, 1; got != want { - t.Fatalf("wrong number of deposed instances with id=foo %d; want %d", got, want) - } - if got, want := bars, 1; got != want { - t.Fatalf("wrong number of deposed instances with id=bar %d; want %d", got, want) - } - } - - // Destroy partially fixed! - destroyFunc = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - s := req.PriorState.AsValueMap() - id := s["id"].AsString() - if id == "foo" || id == "baz" { - resp.NewState = cty.NullVal(req.PriorState.Type()) - } else { - resp.NewState = req.PriorState - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("destroy partially failed")) - } - return - } - - createdInstanceId = "qux" - ctx = testContext2(t, &ContextOpts{ - Providers: ps, - }) - plan, diags = ctx.Plan(m, state, &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "require_new": &InputValue{ - Value: cty.StringVal("qux"), - }, - }, - }) - assertNoErrors(t, diags) - - state, diags = ctx.Apply(plan, m) - // Expect error because 1/2 of Deposed destroys failed - if !diags.HasErrors() { - t.Fatal("should have error") - } - - // foo and baz are now gone, bar sticks around - checkStateString(t, state, ` -aws_instance.web: (1 deposed) - ID = qux - provider = provider["registry.terraform.io/hashicorp/aws"] - require_new = qux - Deposed ID 1 = bar - `) - - // Destroy working fully! - destroyFunc = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - resp.NewState = cty.NullVal(req.PriorState.Type()) - return - } - - createdInstanceId = "quux" - ctx = testContext2(t, &ContextOpts{ - Providers: ps, - }) - plan, diags = ctx.Plan(m, state, &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "require_new": &InputValue{ - Value: cty.StringVal("quux"), - }, - }, - }) - assertNoErrors(t, diags) - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatal("should not have error:", diags.Err()) - } - - // And finally the state is clean - checkStateString(t, state, ` -aws_instance.web: - ID = quux - provider = provider["registry.terraform.io/hashicorp/aws"] - require_new = quux - `) -} - -// Verify that a normal provisioner with on_failure "continue" set won't -// taint the resource and continues executing. -func TestContext2Apply_provisionerFailContinue(t *testing.T) { - m := testModule(t, "apply-provisioner-fail-continue") - p := testProvider("aws") - pr := testProvisioner() - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - - pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provisioner error")) - return - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Provisioners: map[string]provisioners.Factory{ - "shell": testProvisionerFuncFixed(pr), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - checkStateString(t, state, ` -aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = bar - type = aws_instance - `) - - // Verify apply was invoked - if !pr.ProvisionResourceCalled { - t.Fatalf("provisioner not invoked") - } -} - -// Verify that a normal provisioner with on_failure "continue" records -// the error with the hook. -func TestContext2Apply_provisionerFailContinueHook(t *testing.T) { - h := new(MockHook) - m := testModule(t, "apply-provisioner-fail-continue") - p := testProvider("aws") - pr := testProvisioner() - p.PlanResourceChangeFn = testDiffFn - pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provisioner error")) - return - } - - ctx := testContext2(t, &ContextOpts{ - Hooks: []Hook{h}, - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Provisioners: map[string]provisioners.Factory{ - "shell": testProvisionerFuncFixed(pr), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - if _, diags := ctx.Apply(plan, m); diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } - - if !h.PostProvisionInstanceStepCalled { - t.Fatal("PostProvisionInstanceStep not called") - } - if h.PostProvisionInstanceStepErrorArg == nil { - t.Fatal("should have error") - } -} - -func TestContext2Apply_provisionerDestroy(t *testing.T) { - m := testModule(t, "apply-provisioner-destroy") - p := testProvider("aws") - pr := testProvisioner() - p.PlanResourceChangeFn = testDiffFn - pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) { - val := req.Config.GetAttr("command").AsString() - if val != "destroy a bar" { - t.Fatalf("bad value for foo: %q", val) - } - - return - } - - state := states.NewState() - root := state.RootModule() - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr(`aws_instance.foo["a"]`).Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar","foo":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Provisioners: map[string]provisioners.Factory{ - "shell": testProvisionerFuncFixed(pr), - }, - }) - - plan, diags := ctx.Plan(m, state, SimplePlanOpts(plans.DestroyMode, testInputValuesUnset(m.Module.Variables))) - assertNoErrors(t, diags) - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - checkStateString(t, state, ``) - - // Verify apply was invoked - if !pr.ProvisionResourceCalled { - t.Fatalf("provisioner not invoked") - } -} - -// Verify that on destroy provisioner failure, nothing happens to the instance -func TestContext2Apply_provisionerDestroyFail(t *testing.T) { - m := testModule(t, "apply-provisioner-destroy") - p := testProvider("aws") - pr := testProvisioner() - p.PlanResourceChangeFn = testDiffFn - pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provisioner error")) - return - } - - state := states.NewState() - root := state.RootModule() - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr(`aws_instance.foo["a"]`).Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar","foo":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Provisioners: map[string]provisioners.Factory{ - "shell": testProvisionerFuncFixed(pr), - }, - }) - - plan, diags := ctx.Plan(m, state, SimplePlanOpts(plans.DestroyMode, testInputValuesUnset(m.Module.Variables))) - assertNoErrors(t, diags) - - state, diags = ctx.Apply(plan, m) - if diags == nil { - t.Fatal("should error") - } - - checkStateString(t, state, ` -aws_instance.foo["a"]: - ID = bar - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = bar - `) - - // Verify apply was invoked - if !pr.ProvisionResourceCalled { - t.Fatalf("provisioner not invoked") - } -} - -// Verify that on destroy provisioner failure with "continue" that -// we continue to the next provisioner. -func TestContext2Apply_provisionerDestroyFailContinue(t *testing.T) { - m := testModule(t, "apply-provisioner-destroy-continue") - p := testProvider("aws") - pr := testProvisioner() - p.PlanResourceChangeFn = testDiffFn - - var l sync.Mutex - var calls []string - pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) { - val := req.Config.GetAttr("command") - if val.IsNull() { - t.Fatalf("bad value for foo: %#v", val) - } - - l.Lock() - defer l.Unlock() - calls = append(calls, val.AsString()) - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provisioner error")) - return - } - - state := states.NewState() - root := state.RootModule() - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr(`aws_instance.foo["a"]`).Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Provisioners: map[string]provisioners.Factory{ - "shell": testProvisionerFuncFixed(pr), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - assertNoErrors(t, diags) - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - checkStateString(t, state, ``) - - // Verify apply was invoked - if !pr.ProvisionResourceCalled { - t.Fatalf("provisioner not invoked") - } - - expected := []string{"one", "two"} - if !reflect.DeepEqual(calls, expected) { - t.Fatalf("wrong commands\ngot: %#v\nwant: %#v", calls, expected) - } -} - -// Verify that on destroy provisioner failure with "continue" that -// we continue to the next provisioner. But if the next provisioner defines -// to fail, then we fail after running it. -func TestContext2Apply_provisionerDestroyFailContinueFail(t *testing.T) { - m := testModule(t, "apply-provisioner-destroy-fail") - p := testProvider("aws") - pr := testProvisioner() - p.PlanResourceChangeFn = testDiffFn - - var l sync.Mutex - var calls []string - pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) { - val := req.Config.GetAttr("command") - if val.IsNull() { - t.Fatalf("bad value for foo: %#v", val) - } - - l.Lock() - defer l.Unlock() - calls = append(calls, val.AsString()) - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provisioner error")) - return - } - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Provisioners: map[string]provisioners.Factory{ - "shell": testProvisionerFuncFixed(pr), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - assertNoErrors(t, diags) - - state, diags = ctx.Apply(plan, m) - if diags == nil { - t.Fatal("apply succeeded; wanted error from second provisioner") - } - - checkStateString(t, state, ` -aws_instance.foo: - ID = bar - provider = provider["registry.terraform.io/hashicorp/aws"] - `) - - // Verify apply was invoked - if !pr.ProvisionResourceCalled { - t.Fatalf("provisioner not invoked") - } - - expected := []string{"one", "two"} - if !reflect.DeepEqual(calls, expected) { - t.Fatalf("bad: %#v", calls) - } -} - -// Verify destroy provisioners are not run for tainted instances. -func TestContext2Apply_provisionerDestroyTainted(t *testing.T) { - m := testModule(t, "apply-provisioner-destroy") - p := testProvider("aws") - pr := testProvisioner() - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - - destroyCalled := false - pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) { - expected := "create a b" - val := req.Config.GetAttr("command") - if val.AsString() != expected { - t.Fatalf("bad value for command: %#v", val) - } - - return - } - - state := states.NewState() - root := state.RootModule() - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr(`aws_instance.foo["a"]`).Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectTainted, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Provisioners: map[string]provisioners.Factory{ - "shell": testProvisionerFuncFixed(pr), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "input": &InputValue{ - Value: cty.MapVal(map[string]cty.Value{ - "a": cty.StringVal("b"), - }), - SourceType: ValueFromInput, - }, - }, - }) - assertNoErrors(t, diags) - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - checkStateString(t, state, ` -aws_instance.foo["a"]: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = bar - type = aws_instance - `) - - // Verify apply was invoked - if !pr.ProvisionResourceCalled { - t.Fatalf("provisioner not invoked") - } - - if destroyCalled { - t.Fatal("destroy should not be called") - } -} - -func TestContext2Apply_provisionerResourceRef(t *testing.T) { - m := testModule(t, "apply-provisioner-resource-ref") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - - pr := testProvisioner() - pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) { - val := req.Config.GetAttr("command") - if val.AsString() != "2" { - t.Fatalf("bad value for command: %#v", val) - } - - return - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Provisioners: map[string]provisioners.Factory{ - "shell": testProvisionerFuncFixed(pr), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyProvisionerResourceRefStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } - - // Verify apply was invoked - if !pr.ProvisionResourceCalled { - t.Fatalf("provisioner not invoked") - } -} - -func TestContext2Apply_provisionerSelfRef(t *testing.T) { - m := testModule(t, "apply-provisioner-self-ref") - p := testProvider("aws") - pr := testProvisioner() - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) { - val := req.Config.GetAttr("command") - if val.AsString() != "bar" { - t.Fatalf("bad value for command: %#v", val) - } - - return - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Provisioners: map[string]provisioners.Factory{ - "shell": testProvisionerFuncFixed(pr), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyProvisionerSelfRefStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } - - // Verify apply was invoked - if !pr.ProvisionResourceCalled { - t.Fatalf("provisioner not invoked") - } -} - -func TestContext2Apply_provisionerMultiSelfRef(t *testing.T) { - var lock sync.Mutex - commands := make([]string, 0, 5) - - m := testModule(t, "apply-provisioner-multi-self-ref") - p := testProvider("aws") - pr := testProvisioner() - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) { - lock.Lock() - defer lock.Unlock() - - val := req.Config.GetAttr("command") - if val.IsNull() { - t.Fatalf("bad value for command: %#v", val) - } - - commands = append(commands, val.AsString()) - return - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Provisioners: map[string]provisioners.Factory{ - "shell": testProvisionerFuncFixed(pr), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyProvisionerMultiSelfRefStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } - - // Verify apply was invoked - if !pr.ProvisionResourceCalled { - t.Fatalf("provisioner not invoked") - } - - // Verify our result - sort.Strings(commands) - expectedCommands := []string{"number 0", "number 1", "number 2"} - if !reflect.DeepEqual(commands, expectedCommands) { - t.Fatalf("bad: %#v", commands) - } -} - -func TestContext2Apply_provisionerMultiSelfRefSingle(t *testing.T) { - var lock sync.Mutex - order := make([]string, 0, 5) - - m := testModule(t, "apply-provisioner-multi-self-ref-single") - p := testProvider("aws") - pr := testProvisioner() - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) { - lock.Lock() - defer lock.Unlock() - - val := req.Config.GetAttr("order") - if val.IsNull() { - t.Fatalf("no val for order") - } - - order = append(order, val.AsString()) - return - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Provisioners: map[string]provisioners.Factory{ - "shell": testProvisionerFuncFixed(pr), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyProvisionerMultiSelfRefSingleStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } - - // Verify apply was invoked - if !pr.ProvisionResourceCalled { - t.Fatalf("provisioner not invoked") - } - - // Verify our result - sort.Strings(order) - expectedOrder := []string{"0", "1", "2"} - if !reflect.DeepEqual(order, expectedOrder) { - t.Fatalf("bad: %#v", order) - } -} - -func TestContext2Apply_provisionerExplicitSelfRef(t *testing.T) { - m := testModule(t, "apply-provisioner-explicit-self-ref") - p := testProvider("aws") - pr := testProvisioner() - p.PlanResourceChangeFn = testDiffFn - pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) { - val := req.Config.GetAttr("command") - if val.IsNull() || val.AsString() != "bar" { - t.Fatalf("bad value for command: %#v", val) - } - - return - } - - var state *states.State - { - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Provisioners: map[string]provisioners.Factory{ - "shell": testProvisionerFuncFixed(pr), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - // Verify apply was invoked - if !pr.ProvisionResourceCalled { - t.Fatalf("provisioner not invoked") - } - } - - { - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Provisioners: map[string]provisioners.Factory{ - "shell": testProvisionerFuncFixed(pr), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - checkStateString(t, state, ``) - } -} - -func TestContext2Apply_provisionerForEachSelfRef(t *testing.T) { - m := testModule(t, "apply-provisioner-for-each-self") - p := testProvider("aws") - pr := testProvisioner() - p.PlanResourceChangeFn = testDiffFn - - pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) { - val := req.Config.GetAttr("command") - if val.IsNull() { - t.Fatalf("bad value for command: %#v", val) - } - - return resp - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Provisioners: map[string]provisioners.Factory{ - "shell": testProvisionerFuncFixed(pr), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - _, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } -} - -// Provisioner should NOT run on a diff, only create -func TestContext2Apply_Provisioner_Diff(t *testing.T) { - m := testModule(t, "apply-provisioner-diff") - p := testProvider("aws") - pr := testProvisioner() - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Provisioners: map[string]provisioners.Factory{ - "shell": testProvisionerFuncFixed(pr), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - logDiagnostics(t, diags) - t.Fatal("apply failed") - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyProvisionerDiffStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } - - // Verify apply was invoked - if !pr.ProvisionResourceCalled { - t.Fatalf("provisioner was not called on first apply") - } - pr.ProvisionResourceCalled = false - - // Change the state to force a diff - mod := state.RootModule() - obj := mod.Resources["aws_instance.bar"].Instances[addrs.NoKey].Current - var attrs map[string]interface{} - err := json.Unmarshal(obj.AttrsJSON, &attrs) - if err != nil { - t.Fatal(err) - } - attrs["foo"] = "baz" - obj.AttrsJSON, err = json.Marshal(attrs) - if err != nil { - t.Fatal(err) - } - - // Re-create context with state - ctx = testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Provisioners: map[string]provisioners.Factory{ - "shell": testProvisionerFuncFixed(pr), - }, - }) - - plan, diags = ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - state2, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - logDiagnostics(t, diags) - t.Fatal("apply failed") - } - - actual = strings.TrimSpace(state2.String()) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } - - // Verify apply was NOT invoked - if pr.ProvisionResourceCalled { - t.Fatalf("provisioner was called on second apply; should not have been") - } -} - -func TestContext2Apply_outputDiffVars(t *testing.T) { - m := testModule(t, "apply-good") - p := testProvider("aws") - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.baz").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - p.PlanResourceChangeFn = testDiffFn - //func(info *InstanceInfo, s *InstanceState, rc *ResourceConfig) (*InstanceDiff, error) { - // d := &InstanceDiff{ - // Attributes: map[string]*ResourceAttrDiff{}, - // } - // if new, ok := rc.Get("value"); ok { - // d.Attributes["value"] = &ResourceAttrDiff{ - // New: new.(string), - // } - // } - // if new, ok := rc.Get("foo"); ok { - // d.Attributes["foo"] = &ResourceAttrDiff{ - // New: new.(string), - // } - // } else if rc.IsComputed("foo") { - // d.Attributes["foo"] = &ResourceAttrDiff{ - // NewComputed: true, - // Type: DiffAttrOutput, // This doesn't actually really do anything anymore, but this test originally set it. - // } - // } - // if new, ok := rc.Get("num"); ok { - // d.Attributes["num"] = &ResourceAttrDiff{ - // New: fmt.Sprintf("%#v", new), - // } - // } - // return d, nil - //} - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - _, diags = ctx.Apply(plan, m) - assertNoErrors(t, diags) -} - -func TestContext2Apply_destroyX(t *testing.T) { - m := testModule(t, "apply-destroy") - h := new(HookRecordApplyOrder) - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Hooks: []Hook{h}, - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - // First plan and apply a create operation - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - // Next, plan and apply a destroy operation - h.Active = true - ctx = testContext2(t, &ContextOpts{ - Hooks: []Hook{h}, - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags = ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - assertNoErrors(t, diags) - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - // Test that things were destroyed - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyDestroyStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } - - // Test that things were destroyed _in the right order_ - expected2 := []string{"aws_instance.bar", "aws_instance.foo"} - actual2 := h.IDs - if !reflect.DeepEqual(actual2, expected2) { - t.Fatalf("expected: %#v\n\ngot:%#v", expected2, actual2) - } -} - -func TestContext2Apply_destroyOrder(t *testing.T) { - m := testModule(t, "apply-destroy") - h := new(HookRecordApplyOrder) - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Hooks: []Hook{h}, - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - // First plan and apply a create operation - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - t.Logf("State 1: %s", state) - - // Next, plan and apply a destroy - h.Active = true - ctx = testContext2(t, &ContextOpts{ - Hooks: []Hook{h}, - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags = ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - assertNoErrors(t, diags) - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - // Test that things were destroyed - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyDestroyStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } - - // Test that things were destroyed _in the right order_ - expected2 := []string{"aws_instance.bar", "aws_instance.foo"} - actual2 := h.IDs - if !reflect.DeepEqual(actual2, expected2) { - t.Fatalf("expected: %#v\n\ngot:%#v", expected2, actual2) - } -} - -// https://github.com/hashicorp/terraform/issues/2767 -func TestContext2Apply_destroyModulePrefix(t *testing.T) { - m := testModule(t, "apply-destroy-module-resource-prefix") - h := new(MockHook) - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Hooks: []Hook{h}, - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - // First plan and apply a create operation - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - // Verify that we got the apply info correct - if v := h.PreApplyAddr.String(); v != "module.child.aws_instance.foo" { - t.Fatalf("bad: %s", v) - } - - // Next, plan and apply a destroy operation and reset the hook - h = new(MockHook) - ctx = testContext2(t, &ContextOpts{ - Hooks: []Hook{h}, - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags = ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - assertNoErrors(t, diags) - - _, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - // Test that things were destroyed - if v := h.PreApplyAddr.String(); v != "module.child.aws_instance.foo" { - t.Fatalf("bad: %s", v) - } -} - -func TestContext2Apply_destroyNestedModule(t *testing.T) { - m := testModule(t, "apply-destroy-nested-module") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - // First plan and apply a create operation - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - s, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - // Test that things were destroyed - actual := strings.TrimSpace(s.String()) - if actual != "" { - t.Fatalf("expected no state, got: %s", actual) - } -} - -func TestContext2Apply_destroyDeeplyNestedModule(t *testing.T) { - m := testModule(t, "apply-destroy-deeply-nested-module") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - // First plan and apply a create operation - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - s, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - // Test that things were destroyed - if !s.Empty() { - t.Fatalf("wrong final state %s\nwant empty state", spew.Sdump(s)) - } -} - -// https://github.com/hashicorp/terraform/issues/5440 -func TestContext2Apply_destroyModuleWithAttrsReferencingResource(t *testing.T) { - m, snap := testModuleWithSnapshot(t, "apply-destroy-module-with-attrs") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - var state *states.State - { - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - // First plan and apply a create operation - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("plan diags: %s", diags.Err()) - } else { - t.Logf("Step 1 plan: %s", legacyDiffComparisonString(plan.Changes)) - } - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("apply errs: %s", diags.Err()) - } - - t.Logf("Step 1 state: %s", state) - } - - h := new(HookRecordApplyOrder) - h.Active = true - - { - ctx := testContext2(t, &ContextOpts{ - Hooks: []Hook{h}, - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - // First plan and apply a create operation - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - if diags.HasErrors() { - t.Fatalf("destroy plan err: %s", diags.Err()) - } - - t.Logf("Step 2 plan: %s", legacyDiffComparisonString(plan.Changes)) - - ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan) - if err != nil { - t.Fatalf("failed to round-trip through planfile: %s", err) - } - - ctxOpts.Providers = map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - } - - ctx, diags = NewContext(ctxOpts) - if diags.HasErrors() { - t.Fatalf("err: %s", diags.Err()) - } - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("destroy apply err: %s", diags.Err()) - } - - t.Logf("Step 2 state: %s", state) - } - - //Test that things were destroyed - if state.HasManagedResourceInstanceObjects() { - t.Fatal("expected empty state, got:", state) - } -} - -func TestContext2Apply_destroyWithModuleVariableAndCount(t *testing.T) { - m, snap := testModuleWithSnapshot(t, "apply-destroy-mod-var-and-count") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - var state *states.State - { - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - // First plan and apply a create operation - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("apply err: %s", diags.Err()) - } - } - - h := new(HookRecordApplyOrder) - h.Active = true - - { - ctx := testContext2(t, &ContextOpts{ - Hooks: []Hook{h}, - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - // First plan and apply a create operation - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - if diags.HasErrors() { - t.Fatalf("destroy plan err: %s", diags.Err()) - } - - ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan) - if err != nil { - t.Fatalf("failed to round-trip through planfile: %s", err) - } - - ctxOpts.Providers = - map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - } - - ctx, diags = NewContext(ctxOpts) - if diags.HasErrors() { - t.Fatalf("err: %s", diags.Err()) - } - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("destroy apply err: %s", diags.Err()) - } - } - - //Test that things were destroyed - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(` -`) - if actual != expected { - t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual) - } -} - -func TestContext2Apply_destroyTargetWithModuleVariableAndCount(t *testing.T) { - m := testModule(t, "apply-destroy-mod-var-and-count") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - var state *states.State - { - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - // First plan and apply a create operation - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("apply err: %s", diags.Err()) - } - } - - { - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - Targets: []addrs.Targetable{ - addrs.RootModuleInstance.Child("child", addrs.NoKey), - }, - }) - if diags.HasErrors() { - t.Fatalf("plan err: %s", diags) - } - if len(diags) != 1 { - // Should have one warning that -target is in effect. - t.Fatalf("got %d diagnostics in plan; want 1", len(diags)) - } - if got, want := diags[0].Severity(), tfdiags.Warning; got != want { - t.Errorf("wrong diagnostic severity %#v; want %#v", got, want) - } - if got, want := diags[0].Description().Summary, "Resource targeting is in effect"; got != want { - t.Errorf("wrong diagnostic summary %#v; want %#v", got, want) - } - - // Destroy, targeting the module explicitly - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("destroy apply err: %s", diags) - } - if len(diags) != 1 { - t.Fatalf("got %d diagnostics; want 1", len(diags)) - } - if got, want := diags[0].Severity(), tfdiags.Warning; got != want { - t.Errorf("wrong diagnostic severity %#v; want %#v", got, want) - } - if got, want := diags[0].Description().Summary, "Applied changes may be incomplete"; got != want { - t.Errorf("wrong diagnostic summary %#v; want %#v", got, want) - } - } - - //Test that things were destroyed - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(``) - if actual != expected { - t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual) - } -} - -func TestContext2Apply_destroyWithModuleVariableAndCountNested(t *testing.T) { - m, snap := testModuleWithSnapshot(t, "apply-destroy-mod-var-and-count-nested") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - var state *states.State - { - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - // First plan and apply a create operation - plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))) - assertNoErrors(t, diags) - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("apply err: %s", diags.Err()) - } - } - - h := new(HookRecordApplyOrder) - h.Active = true - - { - ctx := testContext2(t, &ContextOpts{ - Hooks: []Hook{h}, - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - // First plan and apply a create operation - plan, diags := ctx.Plan(m, state, SimplePlanOpts(plans.DestroyMode, testInputValuesUnset(m.Module.Variables))) - if diags.HasErrors() { - t.Fatalf("destroy plan err: %s", diags.Err()) - } - - ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan) - if err != nil { - t.Fatalf("failed to round-trip through planfile: %s", err) - } - - ctxOpts.Providers = - map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - } - - ctx, diags = NewContext(ctxOpts) - if diags.HasErrors() { - t.Fatalf("err: %s", diags.Err()) - } - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("destroy apply err: %s", diags.Err()) - } - } - - //Test that things were destroyed - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(` -`) - if actual != expected { - t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual) - } -} - -func TestContext2Apply_destroyOutputs(t *testing.T) { - m := testModule(t, "apply-destroy-outputs") - p := testProvider("test") - p.PlanResourceChangeFn = testDiffFn - - p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse { - // add the required id - m := req.Config.AsValueMap() - m["id"] = cty.StringVal("foo") - - return providers.ReadDataSourceResponse{ - State: cty.ObjectVal(m), - } - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - // First plan and apply a create operation - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - // Next, plan and apply a destroy operation - ctx = testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags = ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - assertNoErrors(t, diags) - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - mod := state.RootModule() - if len(mod.Resources) > 0 { - t.Fatalf("expected no resources, got: %#v", mod) - } - - // destroying again should produce no errors - ctx = testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - plan, diags = ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - assertNoErrors(t, diags) - - if _, diags := ctx.Apply(plan, m); diags.HasErrors() { - t.Fatal(diags.Err()) - } -} - -func TestContext2Apply_destroyOrphan(t *testing.T) { - m := testModule(t, "apply-error") - p := testProvider("aws") - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.baz").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - p.PlanResourceChangeFn = testDiffFn - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - s, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - mod := s.RootModule() - if _, ok := mod.Resources["aws_instance.baz"]; ok { - t.Fatalf("bad: %#v", mod.Resources) - } -} - -func TestContext2Apply_destroyTaintedProvisioner(t *testing.T) { - m := testModule(t, "apply-destroy-provisioner") - p := testProvider("aws") - pr := testProvisioner() - p.PlanResourceChangeFn = testDiffFn - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Provisioners: map[string]provisioners.Factory{ - "shell": testProvisionerFuncFixed(pr), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - assertNoErrors(t, diags) - - s, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - if pr.ProvisionResourceCalled { - t.Fatal("provisioner should not be called") - } - - actual := strings.TrimSpace(s.String()) - expected := strings.TrimSpace("") - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestContext2Apply_error(t *testing.T) { - errored := false - - m := testModule(t, "apply-error") - p := testProvider("aws") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - if errored { - resp.NewState = req.PlannedState - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("error")) - return - } - errored = true - - return testApplyFn(req) - } - p.PlanResourceChangeFn = testDiffFn - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags == nil { - t.Fatal("should have error") - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyErrorStr) - if actual != expected { - t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) - } -} - -func TestContext2Apply_errorDestroy(t *testing.T) { - m := testModule(t, "empty") - p := testProvider("test") - - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test_thing": { - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Optional: true}, - }, - }, - }, - }) - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse { - // Should actually be called for this test, because Terraform Core - // constructs the plan for a destroy operation itself. - return providers.PlanResourceChangeResponse{ - PlannedState: req.ProposedNewState, - } - } - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse { - // The apply (in this case, a destroy) always fails, so we can verify - // that the object stays in the state after a destroy fails even though - // we aren't returning a new state object here. - return providers.ApplyResourceChangeResponse{ - Diagnostics: tfdiags.Diagnostics(nil).Append(fmt.Errorf("failed")), - } - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - state := states.BuildState(func(ss *states.SyncState) { - ss.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_thing", - Name: "foo", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"baz"}`), - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("test"), - Module: addrs.RootModule, - }, - ) - }) - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags = ctx.Apply(plan, m) - if !diags.HasErrors() { - t.Fatal("should have error") - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(` -test_thing.foo: - ID = baz - provider = provider["registry.terraform.io/hashicorp/test"] -`) // test_thing.foo is still here, even though provider returned no new state along with its error - if actual != expected { - t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) - } -} - -func TestContext2Apply_errorCreateInvalidNew(t *testing.T) { - m := testModule(t, "apply-error") - - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "value": {Type: cty.String, Optional: true}, - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - }) - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse { - return providers.PlanResourceChangeResponse{ - PlannedState: req.ProposedNewState, - } - } - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse { - // We're intentionally returning an inconsistent new state here - // because we want to test that Terraform ignores the inconsistency - // when accompanied by another error. - return providers.ApplyResourceChangeResponse{ - NewState: cty.ObjectVal(map[string]cty.Value{ - "value": cty.StringVal("wrong wrong wrong wrong"), - "foo": cty.StringVal("absolutely brimming over with wrongability"), - }), - Diagnostics: tfdiags.Diagnostics(nil).Append(fmt.Errorf("forced error")), - } - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags == nil { - t.Fatal("should have error") - } - if got, want := len(diags), 1; got != want { - // There should be no additional diagnostics generated by Terraform's own eval logic, - // because the provider's own error supersedes them. - t.Errorf("wrong number of diagnostics %d; want %d\n%s", got, want, diags.Err()) - } - if got, want := diags.Err().Error(), "forced error"; !strings.Contains(got, want) { - t.Errorf("returned error does not contain %q, but it should\n%s", want, diags.Err()) - } - if got, want := len(state.RootModule().Resources), 2; got != want { - t.Errorf("%d resources in state before prune; should have %d\n%s", got, want, spew.Sdump(state)) - } - state.PruneResourceHusks() // aws_instance.bar with no instances gets left behind when we bail out, but that's okay - if got, want := len(state.RootModule().Resources), 1; got != want { - t.Errorf("%d resources in state after prune; should have only one (aws_instance.foo, tainted)\n%s", got, spew.Sdump(state)) - } -} - -func TestContext2Apply_errorUpdateNullNew(t *testing.T) { - m := testModule(t, "apply-error") - - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "value": {Type: cty.String, Optional: true}, - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - }) - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse { - return providers.PlanResourceChangeResponse{ - PlannedState: req.ProposedNewState, - } - } - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse { - // We're intentionally returning no NewState here because we want to - // test that Terraform retains the prior state, rather than treating - // the returned null as "no state" (object deleted). - return providers.ApplyResourceChangeResponse{ - Diagnostics: tfdiags.Diagnostics(nil).Append(fmt.Errorf("forced error")), - } - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - state := states.BuildState(func(ss *states.SyncState) { - ss.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "foo", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"value":"old"}`), - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("aws"), - Module: addrs.RootModule, - }, - ) - }) - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags = ctx.Apply(plan, m) - if !diags.HasErrors() { - t.Fatal("should have error") - } - if got, want := len(diags), 1; got != want { - // There should be no additional diagnostics generated by Terraform's own eval logic, - // because the provider's own error supersedes them. - t.Errorf("wrong number of diagnostics %d; want %d\n%s", got, want, diags.Err()) - } - if got, want := diags.Err().Error(), "forced error"; !strings.Contains(got, want) { - t.Errorf("returned error does not contain %q, but it should\n%s", want, diags.Err()) - } - state.PruneResourceHusks() - if got, want := len(state.RootModule().Resources), 1; got != want { - t.Fatalf("%d resources in state; should have only one (aws_instance.foo, unmodified)\n%s", got, spew.Sdump(state)) - } - - is := state.ResourceInstance(addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "foo", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)) - if is == nil { - t.Fatalf("aws_instance.foo is not in the state after apply") - } - if got, want := is.Current.AttrsJSON, []byte(`"old"`); !bytes.Contains(got, want) { - t.Fatalf("incorrect attributes for aws_instance.foo\ngot: %s\nwant: JSON containing %s\n\n%s", got, want, spew.Sdump(is)) - } -} - -func TestContext2Apply_errorPartial(t *testing.T) { - errored := false - - m := testModule(t, "apply-error") - p := testProvider("aws") - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar","type":"aws_instance"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - if errored { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("error")) - return - } - errored = true - - return testApplyFn(req) - } - p.PlanResourceChangeFn = testDiffFn - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - s, diags := ctx.Apply(plan, m) - if diags == nil { - t.Fatal("should have error") - } - - mod := s.RootModule() - if len(mod.Resources) != 2 { - t.Fatalf("bad: %#v", mod.Resources) - } - - actual := strings.TrimSpace(s.String()) - expected := strings.TrimSpace(testTerraformApplyErrorPartialStr) - if actual != expected { - t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) - } -} - -func TestContext2Apply_hook(t *testing.T) { - m := testModule(t, "apply-good") - h := new(MockHook) - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Hooks: []Hook{h}, - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - if _, diags := ctx.Apply(plan, m); diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } - - if !h.PreApplyCalled { - t.Fatal("should be called") - } - if !h.PostApplyCalled { - t.Fatal("should be called") - } - if !h.PostStateUpdateCalled { - t.Fatalf("should call post state update") - } -} - -func TestContext2Apply_hookOrphan(t *testing.T) { - m := testModule(t, "apply-blank") - h := new(MockHook) - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Hooks: []Hook{h}, - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - if _, diags := ctx.Apply(plan, m); diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } - - if !h.PreApplyCalled { - t.Fatal("should be called") - } - if !h.PostApplyCalled { - t.Fatal("should be called") - } - if !h.PostStateUpdateCalled { - t.Fatalf("should call post state update") - } -} - -func TestContext2Apply_idAttr(t *testing.T) { - m := testModule(t, "apply-idattr") - p := testProvider("aws") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } - - mod := state.RootModule() - rs, ok := mod.Resources["aws_instance.foo"] - if !ok { - t.Fatal("not in state") - } - var attrs map[string]interface{} - err := json.Unmarshal(rs.Instances[addrs.NoKey].Current.AttrsJSON, &attrs) - if err != nil { - t.Fatal(err) - } - if got, want := attrs["id"], "foo"; got != want { - t.Fatalf("wrong id\ngot: %#v\nwant: %#v", got, want) - } -} - -func TestContext2Apply_outputBasic(t *testing.T) { - m := testModule(t, "apply-output") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyOutputStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestContext2Apply_outputAdd(t *testing.T) { - m1 := testModule(t, "apply-output-add-before") - p1 := testProvider("aws") - p1.ApplyResourceChangeFn = testApplyFn - p1.PlanResourceChangeFn = testDiffFn - ctx1 := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p1), - }, - }) - - plan1, diags := ctx1.Plan(m1, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state1, diags := ctx1.Apply(plan1, m1) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - m2 := testModule(t, "apply-output-add-after") - p2 := testProvider("aws") - p2.ApplyResourceChangeFn = testApplyFn - p2.PlanResourceChangeFn = testDiffFn - ctx2 := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p2), - }, - }) - - plan2, diags := ctx1.Plan(m2, state1, DefaultPlanOpts) - assertNoErrors(t, diags) - - state2, diags := ctx2.Apply(plan2, m2) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - actual := strings.TrimSpace(state2.String()) - expected := strings.TrimSpace(testTerraformApplyOutputAddStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestContext2Apply_outputList(t *testing.T) { - m := testModule(t, "apply-output-list") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyOutputListStr) - if actual != expected { - t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual) - } -} - -func TestContext2Apply_outputMulti(t *testing.T) { - m := testModule(t, "apply-output-multi") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyOutputMultiStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestContext2Apply_outputMultiIndex(t *testing.T) { - m := testModule(t, "apply-output-multi-index") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyOutputMultiIndexStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestContext2Apply_taintX(t *testing.T) { - m := testModule(t, "apply-taint") - p := testProvider("aws") - // destroyCount tests against regression of - // https://github.com/hashicorp/terraform/issues/1056 - var destroyCount = int32(0) - var once sync.Once - simulateProviderDelay := func() { - time.Sleep(10 * time.Millisecond) - } - - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse { - once.Do(simulateProviderDelay) - if req.PlannedState.IsNull() { - atomic.AddInt32(&destroyCount, 1) - } - return testApplyFn(req) - } - p.PlanResourceChangeFn = testDiffFn - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectTainted, - AttrsJSON: []byte(`{"id":"baz","num": "2", "type": "aws_instance"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } else { - t.Logf("plan: %s", legacyDiffComparisonString(plan.Changes)) - } - - s, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - actual := strings.TrimSpace(s.String()) - expected := strings.TrimSpace(testTerraformApplyTaintStr) - if actual != expected { - t.Fatalf("bad:\n%s", actual) - } - - if destroyCount != 1 { - t.Fatalf("Expected 1 destroy, got %d", destroyCount) - } -} - -func TestContext2Apply_taintDep(t *testing.T) { - m := testModule(t, "apply-taint-dep") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectTainted, - AttrsJSON: []byte(`{"id":"baz","num": "2", "type": "aws_instance"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar","num": "2", "type": "aws_instance", "foo": "baz"}`), - Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.foo")}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } else { - t.Logf("plan: %s", legacyDiffComparisonString(plan.Changes)) - } - - s, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - actual := strings.TrimSpace(s.String()) - expected := strings.TrimSpace(testTerraformApplyTaintDepStr) - if actual != expected { - t.Fatalf("bad:\n%s", actual) - } -} - -func TestContext2Apply_taintDepRequiresNew(t *testing.T) { - m := testModule(t, "apply-taint-dep-requires-new") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectTainted, - AttrsJSON: []byte(`{"id":"baz","num": "2", "type": "aws_instance"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar","num": "2", "type": "aws_instance", "foo": "baz"}`), - Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.foo")}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } else { - t.Logf("plan: %s", legacyDiffComparisonString(plan.Changes)) - } - - s, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - actual := strings.TrimSpace(s.String()) - expected := strings.TrimSpace(testTerraformApplyTaintDepRequireNewStr) - if actual != expected { - t.Fatalf("bad:\n%s", actual) - } -} - -func TestContext2Apply_targeted(t *testing.T) { - m := testModule(t, "apply-targeted") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - Targets: []addrs.Targetable{ - addrs.RootModuleInstance.Resource( - addrs.ManagedResourceMode, "aws_instance", "foo", - ), - }, - }) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - mod := state.RootModule() - if len(mod.Resources) != 1 { - t.Fatalf("expected 1 resource, got: %#v", mod.Resources) - } - - checkStateString(t, state, ` -aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - num = 2 - type = aws_instance - `) -} - -func TestContext2Apply_targetedCount(t *testing.T) { - m := testModule(t, "apply-targeted-count") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - Targets: []addrs.Targetable{ - addrs.RootModuleInstance.Resource( - addrs.ManagedResourceMode, "aws_instance", "foo", - ), - }, - }) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - checkStateString(t, state, ` -aws_instance.foo.0: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance -aws_instance.foo.1: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance -aws_instance.foo.2: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance - `) -} - -func TestContext2Apply_targetedCountIndex(t *testing.T) { - m := testModule(t, "apply-targeted-count") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - Targets: []addrs.Targetable{ - addrs.RootModuleInstance.ResourceInstance( - addrs.ManagedResourceMode, "aws_instance", "foo", addrs.IntKey(1), - ), - }, - }) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - checkStateString(t, state, ` -aws_instance.foo.1: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance - `) -} - -func TestContext2Apply_targetedDestroy(t *testing.T) { - m := testModule(t, "destroy-targeted") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.a").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetOutputValue("out", cty.StringVal("bar"), false) - - child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey)) - child.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.b").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"i-bcd345"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - if diags := ctx.Validate(m); diags.HasErrors() { - t.Fatalf("validate errors: %s", diags.Err()) - } - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - Targets: []addrs.Targetable{ - addrs.RootModuleInstance.Resource( - addrs.ManagedResourceMode, "aws_instance", "a", - ), - }, - }) - assertNoErrors(t, diags) - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - mod := state.RootModule() - if len(mod.Resources) != 0 { - t.Fatalf("expected 0 resources, got: %#v", mod.Resources) - } - - // the root output should not get removed; only the targeted resource. - // - // Note: earlier versions of this test expected 0 outputs, but it turns out - // that was because Validate - not apply or destroy - removed the output - // (which depends on the targeted resource) from state. That version of this - // test did not match actual terraform behavior: the output remains in - // state. - // - // The reason it remains in the state is that we prune out the root module - // output values from the destroy graph as part of pruning out the "update" - // nodes for the resources, because otherwise the root module output values - // force the resources to stay in the graph and can therefore cause - // unwanted dependency cycles. - // - // TODO: Future refactoring may enable us to remove the output from state in - // this case, and that would be Just Fine - this test can be modified to - // expect 0 outputs. - if len(mod.OutputValues) != 1 { - t.Fatalf("expected 1 outputs, got: %#v", mod.OutputValues) - } - - // the module instance should remain - mod = state.Module(addrs.RootModuleInstance.Child("child", addrs.NoKey)) - if len(mod.Resources) != 1 { - t.Fatalf("expected 1 resources, got: %#v", mod.Resources) - } -} - -func TestContext2Apply_targetedDestroyCountDeps(t *testing.T) { - m := testModule(t, "apply-destroy-targeted-count") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"i-bcd345"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"i-abc123"}`), - Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.foo")}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - Targets: []addrs.Targetable{ - addrs.RootModuleInstance.Resource( - addrs.ManagedResourceMode, "aws_instance", "foo", - ), - }, - }) - assertNoErrors(t, diags) - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - checkStateString(t, state, ``) -} - -// https://github.com/hashicorp/terraform/issues/4462 -func TestContext2Apply_targetedDestroyModule(t *testing.T) { - m := testModule(t, "apply-targeted-module") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"i-bcd345"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"i-abc123"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey)) - child.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"i-bcd345"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - child.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"i-abc123"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - Targets: []addrs.Targetable{ - addrs.RootModuleInstance.Child("child", addrs.NoKey).Resource( - addrs.ManagedResourceMode, "aws_instance", "foo", - ), - }, - }) - assertNoErrors(t, diags) - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - checkStateString(t, state, ` -aws_instance.bar: - ID = i-abc123 - provider = provider["registry.terraform.io/hashicorp/aws"] -aws_instance.foo: - ID = i-bcd345 - provider = provider["registry.terraform.io/hashicorp/aws"] - -module.child: - aws_instance.bar: - ID = i-abc123 - provider = provider["registry.terraform.io/hashicorp/aws"] - `) -} - -func TestContext2Apply_targetedDestroyCountIndex(t *testing.T) { - m := testModule(t, "apply-targeted-count") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - foo := &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"i-bcd345"}`), - } - bar := &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"i-abc123"}`), - } - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[0]").Resource, - foo, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[1]").Resource, - foo, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[2]").Resource, - foo, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar[0]").Resource, - bar, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar[1]").Resource, - bar, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar[2]").Resource, - bar, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - Targets: []addrs.Targetable{ - addrs.RootModuleInstance.ResourceInstance( - addrs.ManagedResourceMode, "aws_instance", "foo", addrs.IntKey(2), - ), - addrs.RootModuleInstance.ResourceInstance( - addrs.ManagedResourceMode, "aws_instance", "bar", addrs.IntKey(1), - ), - }, - }) - assertNoErrors(t, diags) - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - checkStateString(t, state, ` -aws_instance.bar.0: - ID = i-abc123 - provider = provider["registry.terraform.io/hashicorp/aws"] -aws_instance.bar.2: - ID = i-abc123 - provider = provider["registry.terraform.io/hashicorp/aws"] -aws_instance.foo.0: - ID = i-bcd345 - provider = provider["registry.terraform.io/hashicorp/aws"] -aws_instance.foo.1: - ID = i-bcd345 - provider = provider["registry.terraform.io/hashicorp/aws"] - `) -} - -func TestContext2Apply_targetedModule(t *testing.T) { - m := testModule(t, "apply-targeted-module") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - Targets: []addrs.Targetable{ - addrs.RootModuleInstance.Child("child", addrs.NoKey), - }, - }) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - mod := state.Module(addrs.RootModuleInstance.Child("child", addrs.NoKey)) - if mod == nil { - t.Fatalf("no child module found in the state!\n\n%#v", state) - } - if len(mod.Resources) != 2 { - t.Fatalf("expected 2 resources, got: %#v", mod.Resources) - } - - checkStateString(t, state, ` - -module.child: - aws_instance.bar: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - num = 2 - type = aws_instance - aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - num = 2 - type = aws_instance - `) -} - -// GH-1858 -func TestContext2Apply_targetedModuleDep(t *testing.T) { - m := testModule(t, "apply-targeted-module-dep") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - Targets: []addrs.Targetable{ - addrs.RootModuleInstance.Resource( - addrs.ManagedResourceMode, "aws_instance", "foo", - ), - }, - }) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } else { - t.Logf("Diff: %s", legacyDiffComparisonString(plan.Changes)) - } - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - checkStateString(t, state, ` -aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = foo - type = aws_instance - - Dependencies: - module.child.aws_instance.mod - -module.child: - aws_instance.mod: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance - - Outputs: - - output = foo - `) -} - -// GH-10911 untargeted outputs should not be in the graph, and therefore -// not execute. -func TestContext2Apply_targetedModuleUnrelatedOutputs(t *testing.T) { - m := testModule(t, "apply-targeted-module-unrelated-outputs") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - - state := states.NewState() - _ = state.EnsureModule(addrs.RootModuleInstance.Child("child2", addrs.NoKey)) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.NormalMode, - Targets: []addrs.Targetable{ - addrs.RootModuleInstance.Child("child2", addrs.NoKey), - }, - }) - assertNoErrors(t, diags) - - s, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - // - module.child1's instance_id output is dropped because we don't preserve - // non-root module outputs between runs (they can be recalculated from config) - // - module.child2's instance_id is updated because its dependency is updated - // - child2_id is updated because if its transitive dependency via module.child2 - checkStateString(t, s, ` - -Outputs: - -child2_id = foo - -module.child2: - aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance - - Outputs: - - instance_id = foo -`) -} - -func TestContext2Apply_targetedModuleResource(t *testing.T) { - m := testModule(t, "apply-targeted-module-resource") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - Targets: []addrs.Targetable{ - addrs.RootModuleInstance.Child("child", addrs.NoKey).Resource( - addrs.ManagedResourceMode, "aws_instance", "foo", - ), - }, - }) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - mod := state.Module(addrs.RootModuleInstance.Child("child", addrs.NoKey)) - if mod == nil || len(mod.Resources) != 1 { - t.Fatalf("expected 1 resource, got: %#v", mod) - } - - checkStateString(t, state, ` - -module.child: - aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - num = 2 - type = aws_instance - `) -} - -func TestContext2Apply_targetedResourceOrphanModule(t *testing.T) { - m := testModule(t, "apply-targeted-resource-orphan-module") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - state := states.NewState() - child := state.EnsureModule(addrs.RootModuleInstance.Child("parent", addrs.NoKey)) - child.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"type":"aws_instance"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.NormalMode, - Targets: []addrs.Targetable{ - addrs.RootModuleInstance.Resource( - addrs.ManagedResourceMode, "aws_instance", "foo", - ), - }, - }) - assertNoErrors(t, diags) - - if _, diags := ctx.Apply(plan, m); diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } -} - -func TestContext2Apply_unknownAttribute(t *testing.T) { - m := testModule(t, "apply-unknown") - p := testProvider("aws") - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { - resp = testDiffFn(req) - planned := resp.PlannedState.AsValueMap() - planned["unknown"] = cty.UnknownVal(cty.String) - resp.PlannedState = cty.ObjectVal(planned) - return resp - } - p.ApplyResourceChangeFn = testApplyFn - - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Computed: true}, - "num": {Type: cty.Number, Optional: true}, - "unknown": {Type: cty.String, Computed: true}, - "type": {Type: cty.String, Computed: true}, - }, - }, - }, - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if !diags.HasErrors() { - t.Error("should error, because attribute 'unknown' is still unknown after apply") - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyUnknownAttrStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestContext2Apply_unknownAttributeInterpolate(t *testing.T) { - m := testModule(t, "apply-unknown-interpolate") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - if _, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts); diags == nil { - t.Fatal("should error") - } -} - -func TestContext2Apply_vars(t *testing.T) { - fixture := contextFixtureApplyVars(t) - opts := fixture.ContextOpts() - ctx := testContext2(t, opts) - m := fixture.Config - - diags := ctx.Validate(m) - if len(diags) != 0 { - t.Fatalf("bad: %s", diags.ErrWithWarnings()) - } - - variables := InputValues{ - "foo": &InputValue{ - Value: cty.StringVal("us-east-1"), - SourceType: ValueFromCaller, - }, - "bar": &InputValue{ - // This one is not explicitly set but that's okay because it - // has a declared default, which Terraform Core will use instead. - Value: cty.NilVal, - SourceType: ValueFromCaller, - }, - "test_list": &InputValue{ - Value: cty.ListVal([]cty.Value{ - cty.StringVal("Hello"), - cty.StringVal("World"), - }), - SourceType: ValueFromCaller, - }, - "test_map": &InputValue{ - Value: cty.MapVal(map[string]cty.Value{ - "Hello": cty.StringVal("World"), - "Foo": cty.StringVal("Bar"), - "Baz": cty.StringVal("Foo"), - }), - SourceType: ValueFromCaller, - }, - "amis": &InputValue{ - Value: cty.MapVal(map[string]cty.Value{ - "us-east-1": cty.StringVal("override"), - }), - SourceType: ValueFromCaller, - }, - } - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: variables, - }) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("err: %s", diags.Err()) - } - - got := strings.TrimSpace(state.String()) - want := strings.TrimSpace(testTerraformApplyVarsStr) - if got != want { - t.Errorf("wrong result\n\ngot:\n%s\n\nwant:\n%s", got, want) - } -} - -func TestContext2Apply_varsEnv(t *testing.T) { - fixture := contextFixtureApplyVarsEnv(t) - opts := fixture.ContextOpts() - ctx := testContext2(t, opts) - m := fixture.Config - - diags := ctx.Validate(m) - if len(diags) != 0 { - t.Fatalf("bad: %s", diags.ErrWithWarnings()) - } - - variables := InputValues{ - "string": &InputValue{ - Value: cty.StringVal("baz"), - SourceType: ValueFromEnvVar, - }, - "list": &InputValue{ - Value: cty.ListVal([]cty.Value{ - cty.StringVal("Hello"), - cty.StringVal("World"), - }), - SourceType: ValueFromEnvVar, - }, - "map": &InputValue{ - Value: cty.MapVal(map[string]cty.Value{ - "Hello": cty.StringVal("World"), - "Foo": cty.StringVal("Bar"), - "Baz": cty.StringVal("Foo"), - }), - SourceType: ValueFromEnvVar, - }, - } - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: variables, - }) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("err: %s", diags.Err()) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyVarsEnvStr) - if actual != expected { - t.Errorf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestContext2Apply_createBefore_depends(t *testing.T) { - m := testModule(t, "apply-depends-create-before") - h := new(HookRecordApplyOrder) - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "web", - }.Instance(addrs.NoKey), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar","require_new":"ami-old"}`), - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("aws"), - Module: addrs.RootModule, - }, - ) - - root.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "lb", - }.Instance(addrs.NoKey), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"baz","instance":"bar"}`), - Dependencies: []addrs.ConfigResource{ - { - Resource: addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "web", - }, - Module: addrs.RootModule, - }, - }, - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("aws"), - Module: addrs.RootModule, - }, - ) - - ctx := testContext2(t, &ContextOpts{ - Hooks: []Hook{h}, - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - logDiagnostics(t, diags) - t.Fatal("plan failed") - } else { - t.Logf("plan:\n%s", legacyDiffComparisonString(plan.Changes)) - } - - h.Active = true - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - logDiagnostics(t, diags) - t.Fatal("apply failed") - } - - mod := state.RootModule() - if len(mod.Resources) < 2 { - t.Logf("state after apply:\n%s", state.String()) - t.Fatalf("only %d resources in root module; want at least 2", len(mod.Resources)) - } - - got := strings.TrimSpace(state.String()) - want := strings.TrimSpace(testTerraformApplyDependsCreateBeforeStr) - if got != want { - t.Fatalf("wrong final state\ngot:\n%s\n\nwant:\n%s", got, want) - } - - // Test that things were managed _in the right order_ - order := h.States - - diffs := h.Diffs - if !order[0].IsNull() || diffs[0].Action == plans.Delete { - t.Fatalf("should create new instance first: %#v", order) - } - - if order[1].GetAttr("id").AsString() != "baz" { - t.Fatalf("update must happen after create: %#v", order[1]) - } - - if order[2].GetAttr("id").AsString() != "bar" || diffs[2].Action != plans.Delete { - t.Fatalf("destroy must happen after update: %#v", order[2]) - } -} - -func TestContext2Apply_singleDestroy(t *testing.T) { - m := testModule(t, "apply-depends-create-before") - h := new(HookRecordApplyOrder) - p := testProvider("aws") - invokeCount := 0 - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse { - invokeCount++ - switch invokeCount { - case 1: - if req.PlannedState.IsNull() { - t.Fatalf("should not destroy") - } - if id := req.PlannedState.GetAttr("id"); id.IsKnown() { - t.Fatalf("should not have ID") - } - case 2: - if req.PlannedState.IsNull() { - t.Fatalf("should not destroy") - } - if id := req.PlannedState.GetAttr("id"); id.AsString() != "baz" { - t.Fatalf("should have id") - } - case 3: - if !req.PlannedState.IsNull() { - t.Fatalf("should destroy") - } - default: - t.Fatalf("bad invoke count %d", invokeCount) - } - return testApplyFn(req) - } - - p.PlanResourceChangeFn = testDiffFn - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "web", - }.Instance(addrs.NoKey), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar","require_new":"ami-old"}`), - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("aws"), - Module: addrs.RootModule, - }, - ) - - root.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "lb", - }.Instance(addrs.NoKey), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"baz","instance":"bar"}`), - Dependencies: []addrs.ConfigResource{ - { - Resource: addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "web", - }, - Module: addrs.RootModule, - }, - }, - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("aws"), - Module: addrs.RootModule, - }, - ) - - ctx := testContext2(t, &ContextOpts{ - Hooks: []Hook{h}, - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - h.Active = true - _, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - if invokeCount != 3 { - t.Fatalf("bad: %d", invokeCount) - } -} - -// GH-7824 -func TestContext2Apply_issue7824(t *testing.T) { - p := testProvider("template") - p.PlanResourceChangeFn = testDiffFn - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "template_file": { - Attributes: map[string]*configschema.Attribute{ - "template": {Type: cty.String, Optional: true}, - "__template_requires_new": {Type: cty.Bool, Optional: true}, - }, - }, - }, - }) - - m, snap := testModuleWithSnapshot(t, "issue-7824") - - // Apply cleanly step 0 - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("template"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))) - if diags.HasErrors() { - t.Fatalf("err: %s", diags.Err()) - } - - // Write / Read plan to simulate running it through a Plan file - ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan) - if err != nil { - t.Fatalf("failed to round-trip through planfile: %s", err) - } - - ctxOpts.Providers = - map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("template"): testProviderFuncFixed(p), - } - - ctx, diags = NewContext(ctxOpts) - if diags.HasErrors() { - t.Fatalf("err: %s", diags.Err()) - } - - _, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("err: %s", diags.Err()) - } -} - -// This deals with the situation where a splat expression is used referring -// to another resource whose count is non-constant. -func TestContext2Apply_issue5254(t *testing.T) { - // Create a provider. We use "template" here just to match the repro - // we got from the issue itself. - p := testProvider("template") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "template_file": { - Attributes: map[string]*configschema.Attribute{ - "template": {Type: cty.String, Optional: true}, - "__template_requires_new": {Type: cty.Bool, Optional: true}, - "id": {Type: cty.String, Computed: true}, - "type": {Type: cty.String, Computed: true}, - }, - }, - }, - }) - - // Apply cleanly step 0 - m := testModule(t, "issue-5254/step-0") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("template"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))) - if diags.HasErrors() { - t.Fatalf("err: %s", diags.Err()) - } - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("err: %s", diags.Err()) - } - - m, snap := testModuleWithSnapshot(t, "issue-5254/step-1") - - // Application success. Now make the modification and store a plan - ctx = testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("template"): testProviderFuncFixed(p), - }, - }) - - plan, diags = ctx.Plan(m, state, SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))) - if diags.HasErrors() { - t.Fatalf("err: %s", diags.Err()) - } - - // Write / Read plan to simulate running it through a Plan file - ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan) - if err != nil { - t.Fatalf("failed to round-trip through planfile: %s", err) - } - - ctxOpts.Providers = map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("template"): testProviderFuncFixed(p), - } - - ctx, diags = NewContext(ctxOpts) - if diags.HasErrors() { - t.Fatalf("err: %s", diags.Err()) - } - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("err: %s", diags.Err()) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(` -template_file.child: - ID = foo - provider = provider["registry.terraform.io/hashicorp/template"] - __template_requires_new = true - template = Hi - type = template_file - - Dependencies: - template_file.parent -template_file.parent.0: - ID = foo - provider = provider["registry.terraform.io/hashicorp/template"] - template = Hi - type = template_file -`) - if actual != expected { - t.Fatalf("wrong final state\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestContext2Apply_targetedWithTaintedInState(t *testing.T) { - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - m, snap := testModuleWithSnapshot(t, "apply-tainted-targets") - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.ifailedprovisioners").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectTainted, - AttrsJSON: []byte(`{"id":"ifailedprovisioners"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.NormalMode, - Targets: []addrs.Targetable{ - addrs.RootModuleInstance.Resource( - addrs.ManagedResourceMode, "aws_instance", "iambeingadded", - ), - }, - }) - if diags.HasErrors() { - t.Fatalf("err: %s", diags.Err()) - } - - // Write / Read plan to simulate running it through a Plan file - ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan) - if err != nil { - t.Fatalf("failed to round-trip through planfile: %s", err) - } - - ctxOpts.Providers = map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - } - - ctx, diags = NewContext(ctxOpts) - if diags.HasErrors() { - t.Fatalf("err: %s", diags.Err()) - } - - s, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("err: %s", diags.Err()) - } - - actual := strings.TrimSpace(s.String()) - expected := strings.TrimSpace(` -aws_instance.iambeingadded: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance -aws_instance.ifailedprovisioners: (tainted) - ID = ifailedprovisioners - provider = provider["registry.terraform.io/hashicorp/aws"] - `) - if actual != expected { - t.Fatalf("expected state: \n%s\ngot: \n%s", expected, actual) - } -} - -// Higher level test exposing the bug this covers in -// TestResource_ignoreChangesRequired -func TestContext2Apply_ignoreChangesCreate(t *testing.T) { - m := testModule(t, "apply-ignore-changes-create") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - - instanceSchema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - instanceSchema.Attributes["required_field"] = &configschema.Attribute{ - Type: cty.String, - Required: true, - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } else { - t.Logf(legacyDiffComparisonString(plan.Changes)) - } - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - mod := state.RootModule() - if len(mod.Resources) != 1 { - t.Fatalf("bad: %s", state) - } - - actual := strings.TrimSpace(state.String()) - // Expect no changes from original state - expected := strings.TrimSpace(` -aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - required_field = set - type = aws_instance -`) - if actual != expected { - t.Fatalf("expected:\n%s\ngot:\n%s", expected, actual) - } -} - -func TestContext2Apply_ignoreChangesWithDep(t *testing.T) { - m := testModule(t, "apply-ignore-changes-dep") - p := testProvider("aws") - - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { - resp.PlannedState = req.ProposedNewState - - switch req.TypeName { - case "aws_instance": - resp.RequiresReplace = append(resp.RequiresReplace, cty.Path{cty.GetAttrStep{Name: "ami"}}) - case "aws_eip": - return testDiffFn(req) - default: - t.Fatalf("Unexpected type: %s", req.TypeName) - } - return - } - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[0]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"i-abc123","ami":"ami-abcd1234"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[1]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"i-bcd234","ami":"i-bcd234"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_eip.foo[0]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"eip-abc123","instance":"i-abc123"}`), - Dependencies: []addrs.ConfigResource{ - { - Resource: addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "foo", - }, - Module: addrs.RootModule, - }, - }, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_eip.foo[1]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"eip-bcd234","instance":"i-bcd234"}`), - Dependencies: []addrs.ConfigResource{ - { - Resource: addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "foo", - }, - Module: addrs.RootModule, - }, - }, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state.DeepCopy(), DefaultPlanOpts) - assertNoErrors(t, diags) - - s, diags := ctx.Apply(plan, m) - assertNoErrors(t, diags) - - actual := strings.TrimSpace(s.String()) - expected := strings.TrimSpace(state.String()) - if actual != expected { - t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) - } -} - -func TestContext2Apply_ignoreChangesAll(t *testing.T) { - m := testModule(t, "apply-ignore-changes-all") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - - instanceSchema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - instanceSchema.Attributes["required_field"] = &configschema.Attribute{ - Type: cty.String, - Required: true, - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - logDiagnostics(t, diags) - t.Fatal("plan failed") - } else { - t.Logf(legacyDiffComparisonString(plan.Changes)) - } - - state, diags := ctx.Apply(plan, m) - assertNoErrors(t, diags) - - mod := state.RootModule() - if len(mod.Resources) != 1 { - t.Fatalf("bad: %s", state) - } - - actual := strings.TrimSpace(state.String()) - // Expect no changes from original state - expected := strings.TrimSpace(` -aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - required_field = set - type = aws_instance -`) - if actual != expected { - t.Fatalf("expected:\n%s\ngot:\n%s", expected, actual) - } -} - -// https://github.com/hashicorp/terraform/issues/7378 -func TestContext2Apply_destroyNestedModuleWithAttrsReferencingResource(t *testing.T) { - m, snap := testModuleWithSnapshot(t, "apply-destroy-nested-module-with-attrs") - p := testProvider("null") - p.PlanResourceChangeFn = testDiffFn - - var state *states.State - { - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("null"): testProviderFuncFixed(p), - }, - }) - - // First plan and apply a create operation - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("apply err: %s", diags.Err()) - } - } - - { - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("null"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - if diags.HasErrors() { - t.Fatalf("destroy plan err: %s", diags.Err()) - } - - ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan) - if err != nil { - t.Fatalf("failed to round-trip through planfile: %s", err) - } - - ctxOpts.Providers = map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("null"): testProviderFuncFixed(p), - } - - ctx, diags = NewContext(ctxOpts) - if diags.HasErrors() { - t.Fatalf("err: %s", diags.Err()) - } - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("destroy apply err: %s", diags.Err()) - } - } - - if !state.Empty() { - t.Fatalf("state after apply: %s\nwant empty state", spew.Sdump(state)) - } -} - -// If a data source explicitly depends on another resource, it's because we need -// that resource to be applied first. -func TestContext2Apply_dataDependsOn(t *testing.T) { - p := testProvider("null") - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "null_instance" "write" { - foo = "attribute" -} - -data "null_data_source" "read" { - count = 1 - depends_on = ["null_instance.write"] -} - -resource "null_instance" "depends" { - foo = data.null_data_source.read[0].foo -} -`}) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("null"): testProviderFuncFixed(p), - }, - }) - - // the "provisioner" here writes to this variable, because the intent is to - // create a dependency which can't be viewed through the graph, and depends - // solely on the configuration providing "depends_on" - provisionerOutput := "" - - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse { - // the side effect of the resource being applied - provisionerOutput = "APPLIED" - return testApplyFn(req) - } - - p.PlanResourceChangeFn = testDiffFn - p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse { - return providers.ReadDataSourceResponse{ - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("boop"), - "foo": cty.StringVal(provisionerOutput), - }), - } - } - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - assertNoErrors(t, diags) - - root := state.Module(addrs.RootModuleInstance) - is := root.ResourceInstance(addrs.Resource{ - Mode: addrs.DataResourceMode, - Type: "null_data_source", - Name: "read", - }.Instance(addrs.IntKey(0))) - if is == nil { - t.Fatal("data resource instance is not present in state; should be") - } - var attrs map[string]interface{} - err := json.Unmarshal(is.Current.AttrsJSON, &attrs) - if err != nil { - t.Fatal(err) - } - actual := attrs["foo"] - expected := "APPLIED" - if actual != expected { - t.Fatalf("bad:\n%s", strings.TrimSpace(state.String())) - } - - // run another plan to make sure the data source doesn't show as a change - plan, diags = ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - for _, c := range plan.Changes.Resources { - if c.Action != plans.NoOp { - t.Fatalf("unexpected change for %s", c.Addr) - } - } - - // now we cause a change in the first resource, which should trigger a plan - // in the data source, and the resource that depends on the data source - // must plan a change as well. - m = testModuleInline(t, map[string]string{ - "main.tf": ` -resource "null_instance" "write" { - foo = "new" -} - -data "null_data_source" "read" { - depends_on = ["null_instance.write"] -} - -resource "null_instance" "depends" { - foo = data.null_data_source.read.foo -} -`}) - - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse { - // the side effect of the resource being applied - provisionerOutput = "APPLIED_AGAIN" - return testApplyFn(req) - } - - ctx = testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("null"): testProviderFuncFixed(p), - }, - }) - - plan, diags = ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - expectedChanges := map[string]plans.Action{ - "null_instance.write": plans.Update, - "data.null_data_source.read": plans.Read, - "null_instance.depends": plans.Update, - } - - for _, c := range plan.Changes.Resources { - if c.Action != expectedChanges[c.Addr.String()] { - t.Errorf("unexpected %s for %s", c.Action, c.Addr) - } - } -} - -func TestContext2Apply_terraformWorkspace(t *testing.T) { - m := testModule(t, "apply-terraform-workspace") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - ctx := testContext2(t, &ContextOpts{ - Meta: &ContextMeta{Env: "foo"}, - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - actual := state.RootModule().OutputValues["output"] - expected := cty.StringVal("foo") - if actual == nil || actual.Value != expected { - t.Fatalf("wrong value\ngot: %#v\nwant: %#v", actual.Value, expected) - } -} - -// verify that multiple config references only create a single depends_on entry -func TestContext2Apply_multiRef(t *testing.T) { - m := testModule(t, "apply-multi-ref") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("err: %s", diags.Err()) - } - - deps := state.Modules[""].Resources["aws_instance.other"].Instances[addrs.NoKey].Current.Dependencies - if len(deps) != 1 || deps[0].String() != "aws_instance.create" { - t.Fatalf("expected 1 depends_on entry for aws_instance.create, got %q", deps) - } -} - -func TestContext2Apply_targetedModuleRecursive(t *testing.T) { - m := testModule(t, "apply-targeted-module-recursive") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - Targets: []addrs.Targetable{ - addrs.RootModuleInstance.Child("child", addrs.NoKey), - }, - }) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("err: %s", diags.Err()) - } - - mod := state.Module( - addrs.RootModuleInstance.Child("child", addrs.NoKey).Child("subchild", addrs.NoKey), - ) - if mod == nil { - t.Fatalf("no subchild module found in the state!\n\n%#v", state) - } - if len(mod.Resources) != 1 { - t.Fatalf("expected 1 resources, got: %#v", mod.Resources) - } - - checkStateString(t, state, ` - -module.child.subchild: - aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - num = 2 - type = aws_instance - `) -} - -func TestContext2Apply_localVal(t *testing.T) { - m := testModule(t, "apply-local-val") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{}, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("error during apply: %s", diags.Err()) - } - - got := strings.TrimSpace(state.String()) - want := strings.TrimSpace(` - -Outputs: - -result_1 = hello -result_3 = hello world -`) - if got != want { - t.Fatalf("wrong final state\ngot:\n%s\nwant:\n%s", got, want) - } -} - -func TestContext2Apply_destroyWithLocals(t *testing.T) { - m := testModule(t, "apply-destroy-with-locals") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetOutputValue("name", cty.StringVal("test-bar"), false) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - assertNoErrors(t, diags) - - s, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("error during apply: %s", diags.Err()) - } - - got := strings.TrimSpace(s.String()) - want := strings.TrimSpace(``) - if got != want { - t.Fatalf("wrong final state\ngot:\n%s\nwant:\n%s", got, want) - } -} - -func TestContext2Apply_providerWithLocals(t *testing.T) { - m := testModule(t, "provider-with-locals") - p := testProvider("aws") - - providerRegion := "" - // this should not be overridden during destroy - p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) { - val := req.Config.GetAttr("region") - if !val.IsNull() { - providerRegion = val.AsString() - } - - return - } - - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("err: %s", diags.Err()) - } - - ctx = testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags = ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - assertNoErrors(t, diags) - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("err: %s", diags.Err()) - } - - if state.HasManagedResourceInstanceObjects() { - t.Fatal("expected no state, got:", state) - } - - if providerRegion != "bar" { - t.Fatalf("expected region %q, got: %q", "bar", providerRegion) - } -} - -func TestContext2Apply_destroyWithProviders(t *testing.T) { - m := testModule(t, "destroy-module-with-provider") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - state := states.NewState() - removed := state.EnsureModule(addrs.RootModuleInstance.Child("mod", addrs.NoKey).Child("removed", addrs.NoKey)) - removed.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.child").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"].baz`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - // test that we can't destroy if the provider is missing - if _, diags := ctx.Plan(m, state, &PlanOpts{Mode: plans.DestroyMode}); diags == nil { - t.Fatal("expected plan error, provider.aws.baz doesn't exist") - } - - // correct the state - state.Modules["module.mod.module.removed"].Resources["aws_instance.child"].ProviderConfig = mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"].bar`) - - ctx = testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - assertNoErrors(t, diags) - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("error during apply: %s", diags.Err()) - } - - got := strings.TrimSpace(state.String()) - - want := strings.TrimSpace("") - if got != want { - t.Fatalf("wrong final state\ngot:\n%s\nwant:\n%s", got, want) - } -} - -func TestContext2Apply_providersFromState(t *testing.T) { - m := configs.NewEmptyConfig() - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - implicitProviderState := states.NewState() - impRoot := implicitProviderState.EnsureModule(addrs.RootModuleInstance) - impRoot.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.a").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - aliasedProviderState := states.NewState() - aliasRoot := aliasedProviderState.EnsureModule(addrs.RootModuleInstance) - aliasRoot.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.a").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"].bar`), - ) - - moduleProviderState := states.NewState() - moduleProviderRoot := moduleProviderState.EnsureModule(addrs.RootModuleInstance) - moduleProviderRoot.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.a").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`module.child.provider["registry.terraform.io/hashicorp/aws"]`), - ) - - for _, tc := range []struct { - name string - state *states.State - output string - err bool - }{ - { - name: "add implicit provider", - state: implicitProviderState, - err: false, - output: "", - }, - - // an aliased provider must be in the config to remove a resource - { - name: "add aliased provider", - state: aliasedProviderState, - err: true, - }, - - // a provider in a module implies some sort of config, so this isn't - // allowed even without an alias - { - name: "add unaliased module provider", - state: moduleProviderState, - err: true, - }, - } { - t.Run(tc.name, func(t *testing.T) { - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, tc.state, DefaultPlanOpts) - if tc.err { - if diags == nil { - t.Fatal("expected error") - } else { - return - } - } - if !tc.err && diags.HasErrors() { - t.Fatal(diags.Err()) - } - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - checkStateString(t, state, "") - - }) - } -} - -func TestContext2Apply_plannedInterpolatedCount(t *testing.T) { - m, snap := testModuleWithSnapshot(t, "apply-interpolated-count") - - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - Providers := map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - } - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.test").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: Providers, - }) - - plan, diags := ctx.Plan(m, state, SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))) - if diags.HasErrors() { - t.Fatalf("plan failed: %s", diags.Err()) - } - - // We'll marshal and unmarshal the plan here, to ensure that we have - // a clean new context as would be created if we separately ran - // terraform plan -out=tfplan && terraform apply tfplan - ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan) - if err != nil { - t.Fatalf("failed to round-trip through planfile: %s", err) - } - - ctxOpts.Providers = Providers - ctx, diags = NewContext(ctxOpts) - if diags.HasErrors() { - t.Fatalf("err: %s", diags.Err()) - } - - // Applying the plan should now succeed - _, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("apply failed: %s", diags.Err()) - } -} - -func TestContext2Apply_plannedDestroyInterpolatedCount(t *testing.T) { - m, snap := testModuleWithSnapshot(t, "plan-destroy-interpolated-count") - - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - providers := map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - } - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.a[0]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.a[1]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetOutputValue("out", cty.ListVal([]cty.Value{cty.StringVal("foo"), cty.StringVal("foo")}), false) - - ctx := testContext2(t, &ContextOpts{ - Providers: providers, - }) - - plan, diags := ctx.Plan(m, state, SimplePlanOpts(plans.DestroyMode, testInputValuesUnset(m.Module.Variables))) - if diags.HasErrors() { - t.Fatalf("plan failed: %s", diags.Err()) - } - - // We'll marshal and unmarshal the plan here, to ensure that we have - // a clean new context as would be created if we separately ran - // terraform plan -out=tfplan && terraform apply tfplan - ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan) - if err != nil { - t.Fatalf("failed to round-trip through planfile: %s", err) - } - - ctxOpts.Providers = providers - ctx, diags = NewContext(ctxOpts) - if diags.HasErrors() { - t.Fatalf("err: %s", diags.Err()) - } - - // Applying the plan should now succeed - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("apply failed: %s", diags.Err()) - } - if !state.Empty() { - t.Fatalf("state not empty: %s\n", state) - } -} - -func TestContext2Apply_scaleInMultivarRef(t *testing.T) { - m := testModule(t, "apply-resource-scale-in") - - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - Providers := map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - } - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.one").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.two").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: Providers, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "instance_count": { - Value: cty.NumberIntVal(0), - SourceType: ValueFromCaller, - }, - }, - }) - assertNoErrors(t, diags) - { - addr := mustResourceInstanceAddr("aws_instance.one[0]") - change := plan.Changes.ResourceInstance(addr) - if change == nil { - t.Fatalf("no planned change for %s", addr) - } - // This test was originally written with Terraform v0.11 and earlier - // in mind, so it declares a no-key instance of aws_instance.one, - // but its configuration sets count (to zero) and so we end up first - // moving the no-key instance to the zero key and then planning to - // destroy the zero key. - if got, want := change.PrevRunAddr, mustResourceInstanceAddr("aws_instance.one"); !want.Equal(got) { - t.Errorf("wrong previous run address for %s %s; want %s", addr, got, want) - } - if got, want := change.Action, plans.Delete; got != want { - t.Errorf("wrong action for %s %s; want %s", addr, got, want) - } - if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseCountIndex; got != want { - t.Errorf("wrong action reason for %s %s; want %s", addr, got, want) - } - } - { - addr := mustResourceInstanceAddr("aws_instance.two") - change := plan.Changes.ResourceInstance(addr) - if change == nil { - t.Fatalf("no planned change for %s", addr) - } - if got, want := change.PrevRunAddr, mustResourceInstanceAddr("aws_instance.two"); !want.Equal(got) { - t.Errorf("wrong previous run address for %s %s; want %s", addr, got, want) - } - if got, want := change.Action, plans.Update; got != want { - t.Errorf("wrong action for %s %s; want %s", addr, got, want) - } - if got, want := change.ActionReason, plans.ResourceInstanceChangeNoReason; got != want { - t.Errorf("wrong action reason for %s %s; want %s", addr, got, want) - } - } - - // Applying the plan should now succeed - _, diags = ctx.Apply(plan, m) - assertNoErrors(t, diags) -} - -func TestContext2Apply_inconsistentWithPlan(t *testing.T) { - m := testModule(t, "apply-inconsistent-with-plan") - p := testProvider("test") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test": { - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Computed: true}, - }, - }, - }, - }) - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse { - return providers.PlanResourceChangeResponse{ - PlannedState: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("before"), - }), - } - } - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse { - return providers.ApplyResourceChangeResponse{ - NewState: cty.ObjectVal(map[string]cty.Value{ - // This is intentionally incorrect: because id was fixed at "before" - // during plan, it must not change during apply. - "id": cty.StringVal("after"), - }), - } - } - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - _, diags = ctx.Apply(plan, m) - if !diags.HasErrors() { - t.Fatalf("apply succeeded; want error") - } - if got, want := diags.Err().Error(), "Provider produced inconsistent result after apply"; !strings.Contains(got, want) { - t.Fatalf("wrong error\ngot: %s\nshould contain: %s", got, want) - } -} - -// Issue 19908 was about retaining an existing object in the state when an -// update to it fails and the provider does not return a partially-updated -// value for it. Previously we were incorrectly removing it from the state -// in that case, but instead it should be retained so the update can be -// retried. -func TestContext2Apply_issue19908(t *testing.T) { - m := testModule(t, "apply-issue19908") - p := testProvider("test") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test": { - Attributes: map[string]*configschema.Attribute{ - "baz": {Type: cty.String, Required: true}, - }, - }, - }, - }) - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse { - return providers.PlanResourceChangeResponse{ - PlannedState: req.ProposedNewState, - } - } - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse { - var diags tfdiags.Diagnostics - diags = diags.Append(fmt.Errorf("update failed")) - return providers.ApplyResourceChangeResponse{ - Diagnostics: diags, - } - } - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - state := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test", - Name: "foo", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{"baz":"old"}`), - Status: states.ObjectReady, - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("test"), - Module: addrs.RootModule, - }, - ) - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags = ctx.Apply(plan, m) - if !diags.HasErrors() { - t.Fatalf("apply succeeded; want error") - } - if got, want := diags.Err().Error(), "update failed"; !strings.Contains(got, want) { - t.Fatalf("wrong error\ngot: %s\nshould contain: %s", got, want) - } - - mod := state.RootModule() - rs := mod.Resources["test.foo"] - if rs == nil { - t.Fatalf("test.foo not in state after apply, but should be") - } - is := rs.Instances[addrs.NoKey] - if is == nil { - t.Fatalf("test.foo not in state after apply, but should be") - } - obj := is.Current - if obj == nil { - t.Fatalf("test.foo has no current object in state after apply, but should do") - } - - if got, want := obj.Status, states.ObjectReady; got != want { - t.Errorf("test.foo has wrong status %s after apply; want %s", got, want) - } - if got, want := obj.AttrsJSON, []byte(`"old"`); !bytes.Contains(got, want) { - t.Errorf("test.foo attributes JSON doesn't contain %s after apply\ngot: %s", want, got) - } -} - -func TestContext2Apply_invalidIndexRef(t *testing.T) { - p := testProvider("test") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test_instance": { - Attributes: map[string]*configschema.Attribute{ - "value": {Type: cty.String, Optional: true, Computed: true}, - }, - }, - }, - }) - p.PlanResourceChangeFn = testDiffFn - - m := testModule(t, "apply-invalid-index") - c := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - diags := c.Validate(m) - if diags.HasErrors() { - t.Fatalf("unexpected validation failure: %s", diags.Err()) - } - - wantErr := `The given key does not identify an element in this collection value` - _, diags = c.Plan(m, states.NewState(), DefaultPlanOpts) - - if !diags.HasErrors() { - t.Fatalf("plan succeeded; want error") - } - gotErr := diags.Err().Error() - - if !strings.Contains(gotErr, wantErr) { - t.Fatalf("missing expected error\ngot: %s\n\nwant: error containing %q", gotErr, wantErr) - } -} - -func TestContext2Apply_moduleReplaceCycle(t *testing.T) { - for _, mode := range []string{"normal", "cbd"} { - var m *configs.Config - - switch mode { - case "normal": - m = testModule(t, "apply-module-replace-cycle") - case "cbd": - m = testModule(t, "apply-module-replace-cycle-cbd") - } - - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - instanceSchema := &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Computed: true}, - "require_new": {Type: cty.String, Optional: true}, - }, - } - - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": instanceSchema, - }, - }) - - state := states.NewState() - modA := state.EnsureModule(addrs.RootModuleInstance.Child("a", addrs.NoKey)) - modA.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "a", - }.Instance(addrs.NoKey), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"a","require_new":"old"}`), - CreateBeforeDestroy: mode == "cbd", - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("aws"), - Module: addrs.RootModule, - }, - ) - - modB := state.EnsureModule(addrs.RootModuleInstance.Child("b", addrs.NoKey)) - modB.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "b", - }.Instance(addrs.IntKey(0)), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"b","require_new":"old"}`), - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("aws"), - Module: addrs.RootModule, - }, - ) - - aBefore, _ := plans.NewDynamicValue( - cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("a"), - "require_new": cty.StringVal("old"), - }), instanceSchema.ImpliedType()) - aAfter, _ := plans.NewDynamicValue( - cty.ObjectVal(map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "require_new": cty.StringVal("new"), - }), instanceSchema.ImpliedType()) - bBefore, _ := plans.NewDynamicValue( - cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("b"), - "require_new": cty.StringVal("old"), - }), instanceSchema.ImpliedType()) - bAfter, _ := plans.NewDynamicValue( - cty.ObjectVal(map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "require_new": cty.UnknownVal(cty.String), - }), instanceSchema.ImpliedType()) - - var aAction plans.Action - switch mode { - case "normal": - aAction = plans.DeleteThenCreate - case "cbd": - aAction = plans.CreateThenDelete - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - changes := &plans.Changes{ - Resources: []*plans.ResourceInstanceChangeSrc{ - { - Addr: addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "a", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance.Child("a", addrs.NoKey)), - ProviderAddr: addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("aws"), - Module: addrs.RootModule, - }, - ChangeSrc: plans.ChangeSrc{ - Action: aAction, - Before: aBefore, - After: aAfter, - }, - }, - { - Addr: addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "b", - }.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance.Child("b", addrs.NoKey)), - ProviderAddr: addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("aws"), - Module: addrs.RootModule, - }, - ChangeSrc: plans.ChangeSrc{ - Action: plans.DeleteThenCreate, - Before: bBefore, - After: bAfter, - }, - }, - }, - } - - plan := &plans.Plan{ - UIMode: plans.NormalMode, - Changes: changes, - PriorState: state.DeepCopy(), - PrevRunState: state.DeepCopy(), - } - - t.Run(mode, func(t *testing.T) { - _, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatal(diags.Err()) - } - }) - } -} - -func TestContext2Apply_destroyDataCycle(t *testing.T) { - m, snap := testModuleWithSnapshot(t, "apply-destroy-data-cycle") - p := testProvider("null") - p.PlanResourceChangeFn = testDiffFn - p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse { - return providers.ReadDataSourceResponse{ - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("new"), - "foo": cty.NullVal(cty.String), - }), - } - } - - tp := testProvider("test") - tp.PlanResourceChangeFn = testDiffFn - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "null_resource", - Name: "a", - }.Instance(addrs.IntKey(0)), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"a"}`), - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("null"), - Module: addrs.RootModule, - }, - ) - root.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_resource", - Name: "a", - }.Instance(addrs.IntKey(0)), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"a"}`), - Dependencies: []addrs.ConfigResource{ - { - Resource: addrs.Resource{ - Mode: addrs.DataResourceMode, - Type: "null_data_source", - Name: "d", - }, - Module: addrs.RootModule, - }, - }, - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("test"), - Module: addrs.RootModule, - }, - ) - root.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.DataResourceMode, - Type: "null_data_source", - Name: "d", - }.Instance(addrs.NoKey), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"old"}`), - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("null"), - Module: addrs.RootModule, - }, - ) - - Providers := map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("null"): testProviderFuncFixed(p), - addrs.NewDefaultProvider("test"): testProviderFuncFixed(tp), - } - - ctx := testContext2(t, &ContextOpts{ - Providers: Providers, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - diags.HasErrors() - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - // We'll marshal and unmarshal the plan here, to ensure that we have - // a clean new context as would be created if we separately ran - // terraform plan -out=tfplan && terraform apply tfplan - ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan) - if err != nil { - t.Fatal(err) - } - ctxOpts.Providers = Providers - ctx, diags = NewContext(ctxOpts) - if diags.HasErrors() { - t.Fatalf("failed to create context for plan: %s", diags.Err()) - } - - tp.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) { - foo := req.Config.GetAttr("foo") - if !foo.IsKnown() { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("unknown config value foo")) - return resp - } - - if foo.AsString() != "new" { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("wrong config value: %q", foo.AsString())) - } - return resp - } - - _, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } -} - -func TestContext2Apply_taintedDestroyFailure(t *testing.T) { - m := testModule(t, "apply-destroy-tainted") - p := testProvider("test") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - // All destroys fail. - if req.PlannedState.IsNull() { - resp.Diagnostics = resp.Diagnostics.Append(errors.New("failure")) - return - } - - // c will also fail to create, meaning the existing tainted instance - // becomes deposed, ans is then promoted back to current. - // only C has a foo attribute - planned := req.PlannedState.AsValueMap() - foo, ok := planned["foo"] - if ok && !foo.IsNull() && foo.AsString() == "c" { - resp.Diagnostics = resp.Diagnostics.Append(errors.New("failure")) - return - } - - return testApplyFn(req) - } - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test_instance": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - "foo": { - Type: cty.String, - Optional: true, - }, - }, - }, - }, - }) - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_instance", - Name: "a", - }.Instance(addrs.NoKey), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectTainted, - AttrsJSON: []byte(`{"id":"a","foo":"a"}`), - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("test"), - Module: addrs.RootModule, - }, - ) - root.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_instance", - Name: "b", - }.Instance(addrs.NoKey), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectTainted, - AttrsJSON: []byte(`{"id":"b","foo":"b"}`), - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("test"), - Module: addrs.RootModule, - }, - ) - root.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_instance", - Name: "c", - }.Instance(addrs.NoKey), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectTainted, - AttrsJSON: []byte(`{"id":"c","foo":"old"}`), - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("test"), - Module: addrs.RootModule, - }, - ) - - Providers := map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - } - - ctx := testContext2(t, &ContextOpts{ - Providers: Providers, - Hooks: []Hook{&testHook{}}, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - diags.HasErrors() - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - state, diags = ctx.Apply(plan, m) - if !diags.HasErrors() { - t.Fatal("expected error") - } - - root = state.Module(addrs.RootModuleInstance) - - // the instance that failed to destroy should remain tainted - a := root.ResourceInstance(addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_instance", - Name: "a", - }.Instance(addrs.NoKey)) - - if a.Current.Status != states.ObjectTainted { - t.Fatal("test_instance.a should be tainted") - } - - // b is create_before_destroy, and the destroy failed, so there should be 1 - // deposed instance. - b := root.ResourceInstance(addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_instance", - Name: "b", - }.Instance(addrs.NoKey)) - - if b.Current.Status != states.ObjectReady { - t.Fatal("test_instance.b should be Ready") - } - - if len(b.Deposed) != 1 { - t.Fatal("test_instance.b failed to keep deposed instance") - } - - // the desposed c instance should be promoted back to Current, and remain - // tainted - c := root.ResourceInstance(addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_instance", - Name: "c", - }.Instance(addrs.NoKey)) - - if c.Current == nil { - t.Fatal("test_instance.c has no current instance, but it should") - } - - if c.Current.Status != states.ObjectTainted { - t.Fatal("test_instance.c should be tainted") - } - - if len(c.Deposed) != 0 { - t.Fatal("test_instance.c should have no deposed instances") - } - - if string(c.Current.AttrsJSON) != `{"foo":"old","id":"c"}` { - t.Fatalf("unexpected attrs for c: %q\n", c.Current.AttrsJSON) - } -} - -func TestContext2Apply_plannedConnectionRefs(t *testing.T) { - m := testModule(t, "apply-plan-connection-refs") - p := testProvider("test") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - s := req.PlannedState.AsValueMap() - // delay "a" slightly, so if the reference edge is missing the "b" - // provisioner will see an unknown value. - if s["foo"].AsString() == "a" { - time.Sleep(500 * time.Millisecond) - } - - s["id"] = cty.StringVal("ID") - if ty, ok := s["type"]; ok && !ty.IsKnown() { - s["type"] = cty.StringVal(req.TypeName) - } - resp.NewState = cty.ObjectVal(s) - return resp - } - - provisionerFactory := func() (provisioners.Interface, error) { - pr := testProvisioner() - pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) { - host := req.Connection.GetAttr("host") - if host.IsNull() || !host.IsKnown() { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("invalid host value: %#v", host)) - } - - return resp - } - return pr, nil - } - - Providers := map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - } - - provisioners := map[string]provisioners.Factory{ - "shell": provisionerFactory, - } - - hook := &testHook{} - ctx := testContext2(t, &ContextOpts{ - Providers: Providers, - Provisioners: provisioners, - Hooks: []Hook{hook}, - }) - - plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))) - diags.HasErrors() - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - _, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } -} - -func TestContext2Apply_cbdCycle(t *testing.T) { - m, snap := testModuleWithSnapshot(t, "apply-cbd-cycle") - p := testProvider("test") - p.PlanResourceChangeFn = testDiffFn - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_instance", - Name: "a", - }.Instance(addrs.NoKey), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"a","require_new":"old","foo":"b"}`), - Dependencies: []addrs.ConfigResource{ - { - Resource: addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_instance", - Name: "b", - }, - Module: addrs.RootModule, - }, - { - Resource: addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_instance", - Name: "c", - }, - Module: addrs.RootModule, - }, - }, - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("test"), - Module: addrs.RootModule, - }, - ) - root.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_instance", - Name: "b", - }.Instance(addrs.NoKey), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"b","require_new":"old","foo":"c"}`), - Dependencies: []addrs.ConfigResource{ - { - Resource: addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_instance", - Name: "c", - }, - Module: addrs.RootModule, - }, - }, - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("test"), - Module: addrs.RootModule, - }, - ) - root.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_instance", - Name: "c", - }.Instance(addrs.NoKey), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"c","require_new":"old"}`), - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("test"), - Module: addrs.RootModule, - }, - ) - - Providers := map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - } - - hook := &testHook{} - ctx := testContext2(t, &ContextOpts{ - Providers: Providers, - Hooks: []Hook{hook}, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - diags.HasErrors() - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - // We'll marshal and unmarshal the plan here, to ensure that we have - // a clean new context as would be created if we separately ran - // terraform plan -out=tfplan && terraform apply tfplan - ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan) - if err != nil { - t.Fatal(err) - } - ctxOpts.Providers = Providers - ctx, diags = NewContext(ctxOpts) - if diags.HasErrors() { - t.Fatalf("failed to create context for plan: %s", diags.Err()) - } - - _, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } -} - -func TestContext2Apply_ProviderMeta_apply_set(t *testing.T) { - m := testModule(t, "provider-meta-set") - p := testProvider("test") - p.PlanResourceChangeFn = testDiffFn - schema := p.ProviderSchema() - schema.ProviderMeta = &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "baz": { - Type: cty.String, - Required: true, - }, - }, - } - - var pmMu sync.Mutex - arcPMs := map[string]cty.Value{} - - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse { - pmMu.Lock() - defer pmMu.Unlock() - arcPMs[req.TypeName] = req.ProviderMeta - - s := req.PlannedState.AsValueMap() - s["id"] = cty.StringVal("ID") - if ty, ok := s["type"]; ok && !ty.IsKnown() { - s["type"] = cty.StringVal(req.TypeName) - } - return providers.ApplyResourceChangeResponse{ - NewState: cty.ObjectVal(s), - } - } - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema) - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - _, diags = ctx.Apply(plan, m) - assertNoErrors(t, diags) - - if !p.ApplyResourceChangeCalled { - t.Fatalf("ApplyResourceChange not called") - } - - expectations := map[string]cty.Value{} - - if pm, ok := arcPMs["test_resource"]; !ok { - t.Fatalf("sub-module ApplyResourceChange not called") - } else if pm.IsNull() { - t.Fatalf("null ProviderMeta in sub-module ApplyResourceChange") - } else { - expectations["quux-submodule"] = pm - } - - if pm, ok := arcPMs["test_instance"]; !ok { - t.Fatalf("root module ApplyResourceChange not called") - } else if pm.IsNull() { - t.Fatalf("null ProviderMeta in root module ApplyResourceChange") - } else { - expectations["quux"] = pm - } - - type metaStruct struct { - Baz string `cty:"baz"` - } - - for expected, v := range expectations { - var meta metaStruct - err := gocty.FromCtyValue(v, &meta) - if err != nil { - t.Fatalf("Error parsing cty value: %s", err) - } - if meta.Baz != expected { - t.Fatalf("Expected meta.Baz to be %q, got %q", expected, meta.Baz) - } - } -} - -func TestContext2Apply_ProviderMeta_apply_unset(t *testing.T) { - m := testModule(t, "provider-meta-unset") - p := testProvider("test") - p.PlanResourceChangeFn = testDiffFn - schema := p.ProviderSchema() - schema.ProviderMeta = &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "baz": { - Type: cty.String, - Required: true, - }, - }, - } - var pmMu sync.Mutex - arcPMs := map[string]cty.Value{} - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse { - pmMu.Lock() - defer pmMu.Unlock() - arcPMs[req.TypeName] = req.ProviderMeta - - s := req.PlannedState.AsValueMap() - s["id"] = cty.StringVal("ID") - if ty, ok := s["type"]; ok && !ty.IsKnown() { - s["type"] = cty.StringVal(req.TypeName) - } - return providers.ApplyResourceChangeResponse{ - NewState: cty.ObjectVal(s), - } - } - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema) - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - _, diags = ctx.Apply(plan, m) - assertNoErrors(t, diags) - - if !p.ApplyResourceChangeCalled { - t.Fatalf("ApplyResourceChange not called") - } - - if pm, ok := arcPMs["test_resource"]; !ok { - t.Fatalf("sub-module ApplyResourceChange not called") - } else if !pm.IsNull() { - t.Fatalf("non-null ProviderMeta in sub-module ApplyResourceChange: %+v", pm) - } - - if pm, ok := arcPMs["test_instance"]; !ok { - t.Fatalf("root module ApplyResourceChange not called") - } else if !pm.IsNull() { - t.Fatalf("non-null ProviderMeta in root module ApplyResourceChange: %+v", pm) - } -} - -func TestContext2Apply_ProviderMeta_plan_set(t *testing.T) { - m := testModule(t, "provider-meta-set") - p := testProvider("test") - schema := p.ProviderSchema() - schema.ProviderMeta = &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "baz": { - Type: cty.String, - Required: true, - }, - }, - } - prcPMs := map[string]cty.Value{} - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse { - prcPMs[req.TypeName] = req.ProviderMeta - return providers.PlanResourceChangeResponse{ - PlannedState: req.ProposedNewState, - } - } - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema) - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - _, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - if !p.PlanResourceChangeCalled { - t.Fatalf("PlanResourceChange not called") - } - - expectations := map[string]cty.Value{} - - if pm, ok := prcPMs["test_resource"]; !ok { - t.Fatalf("sub-module PlanResourceChange not called") - } else if pm.IsNull() { - t.Fatalf("null ProviderMeta in sub-module PlanResourceChange") - } else { - expectations["quux-submodule"] = pm - } - - if pm, ok := prcPMs["test_instance"]; !ok { - t.Fatalf("root module PlanResourceChange not called") - } else if pm.IsNull() { - t.Fatalf("null ProviderMeta in root module PlanResourceChange") - } else { - expectations["quux"] = pm - } - - type metaStruct struct { - Baz string `cty:"baz"` - } - - for expected, v := range expectations { - var meta metaStruct - err := gocty.FromCtyValue(v, &meta) - if err != nil { - t.Fatalf("Error parsing cty value: %s", err) - } - if meta.Baz != expected { - t.Fatalf("Expected meta.Baz to be %q, got %q", expected, meta.Baz) - } - } -} - -func TestContext2Apply_ProviderMeta_plan_unset(t *testing.T) { - m := testModule(t, "provider-meta-unset") - p := testProvider("test") - schema := p.ProviderSchema() - schema.ProviderMeta = &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "baz": { - Type: cty.String, - Required: true, - }, - }, - } - prcPMs := map[string]cty.Value{} - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse { - prcPMs[req.TypeName] = req.ProviderMeta - return providers.PlanResourceChangeResponse{ - PlannedState: req.ProposedNewState, - } - } - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema) - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - _, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - if !p.PlanResourceChangeCalled { - t.Fatalf("PlanResourceChange not called") - } - - if pm, ok := prcPMs["test_resource"]; !ok { - t.Fatalf("sub-module PlanResourceChange not called") - } else if !pm.IsNull() { - t.Fatalf("non-null ProviderMeta in sub-module PlanResourceChange: %+v", pm) - } - - if pm, ok := prcPMs["test_instance"]; !ok { - t.Fatalf("root module PlanResourceChange not called") - } else if !pm.IsNull() { - t.Fatalf("non-null ProviderMeta in root module PlanResourceChange: %+v", pm) - } -} - -func TestContext2Apply_ProviderMeta_plan_setNoSchema(t *testing.T) { - m := testModule(t, "provider-meta-set") - p := testProvider("test") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - _, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if !diags.HasErrors() { - t.Fatalf("plan supposed to error, has no errors") - } - - var rootErr, subErr bool - errorSummary := "The resource test_%s.bar belongs to a provider that doesn't support provider_meta blocks" - for _, diag := range diags { - if diag.Description().Summary != "Provider registry.terraform.io/hashicorp/test doesn't support provider_meta" { - t.Errorf("Unexpected error: %+v", diag.Description()) - } - switch diag.Description().Detail { - case fmt.Sprintf(errorSummary, "instance"): - rootErr = true - case fmt.Sprintf(errorSummary, "resource"): - subErr = true - default: - t.Errorf("Unexpected error: %s", diag.Description()) - } - } - if !rootErr { - t.Errorf("Expected unsupported provider_meta block error for root module, none received") - } - if !subErr { - t.Errorf("Expected unsupported provider_meta block error for sub-module, none received") - } -} - -func TestContext2Apply_ProviderMeta_plan_setInvalid(t *testing.T) { - m := testModule(t, "provider-meta-set") - p := testProvider("test") - p.PlanResourceChangeFn = testDiffFn - schema := p.ProviderSchema() - schema.ProviderMeta = &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "quux": { - Type: cty.String, - Required: true, - }, - }, - } - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema) - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - _, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if !diags.HasErrors() { - t.Fatalf("plan supposed to error, has no errors") - } - - var reqErr, invalidErr bool - for _, diag := range diags { - switch diag.Description().Summary { - case "Missing required argument": - if diag.Description().Detail == `The argument "quux" is required, but no definition was found.` { - reqErr = true - } else { - t.Errorf("Unexpected error %+v", diag.Description()) - } - case "Unsupported argument": - if diag.Description().Detail == `An argument named "baz" is not expected here.` { - invalidErr = true - } else { - t.Errorf("Unexpected error %+v", diag.Description()) - } - default: - t.Errorf("Unexpected error %+v", diag.Description()) - } - } - if !reqErr { - t.Errorf("Expected missing required argument error, none received") - } - if !invalidErr { - t.Errorf("Expected unsupported argument error, none received") - } -} - -func TestContext2Apply_ProviderMeta_refresh_set(t *testing.T) { - m := testModule(t, "provider-meta-set") - p := testProvider("test") - p.PlanResourceChangeFn = testDiffFn - schema := p.ProviderSchema() - schema.ProviderMeta = &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "baz": { - Type: cty.String, - Required: true, - }, - }, - } - rrcPMs := map[string]cty.Value{} - p.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) { - rrcPMs[req.TypeName] = req.ProviderMeta - newState, err := p.GetProviderSchemaResponse.ResourceTypes[req.TypeName].Block.CoerceValue(req.PriorState) - if err != nil { - panic(err) - } - resp.NewState = newState - return resp - } - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema) - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - assertNoErrors(t, diags) - - _, diags = ctx.Refresh(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - if !p.ReadResourceCalled { - t.Fatalf("ReadResource not called") - } - - expectations := map[string]cty.Value{} - - if pm, ok := rrcPMs["test_resource"]; !ok { - t.Fatalf("sub-module ReadResource not called") - } else if pm.IsNull() { - t.Fatalf("null ProviderMeta in sub-module ReadResource") - } else { - expectations["quux-submodule"] = pm - } - - if pm, ok := rrcPMs["test_instance"]; !ok { - t.Fatalf("root module ReadResource not called") - } else if pm.IsNull() { - t.Fatalf("null ProviderMeta in root module ReadResource") - } else { - expectations["quux"] = pm - } - - type metaStruct struct { - Baz string `cty:"baz"` - } - - for expected, v := range expectations { - var meta metaStruct - err := gocty.FromCtyValue(v, &meta) - if err != nil { - t.Fatalf("Error parsing cty value: %s", err) - } - if meta.Baz != expected { - t.Fatalf("Expected meta.Baz to be %q, got %q", expected, meta.Baz) - } - } -} - -func TestContext2Apply_ProviderMeta_refresh_setNoSchema(t *testing.T) { - m := testModule(t, "provider-meta-set") - p := testProvider("test") - p.PlanResourceChangeFn = testDiffFn - - // we need a schema for plan/apply so they don't error - schema := p.ProviderSchema() - schema.ProviderMeta = &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "baz": { - Type: cty.String, - Required: true, - }, - }, - } - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema) - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - assertNoErrors(t, diags) - - // drop the schema before refresh, to test that it errors - schema.ProviderMeta = nil - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema) - ctx = testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - _, diags = ctx.Refresh(m, state, DefaultPlanOpts) - if !diags.HasErrors() { - t.Fatalf("refresh supposed to error, has no errors") - } - - var rootErr, subErr bool - errorSummary := "The resource test_%s.bar belongs to a provider that doesn't support provider_meta blocks" - for _, diag := range diags { - if diag.Description().Summary != "Provider registry.terraform.io/hashicorp/test doesn't support provider_meta" { - t.Errorf("Unexpected error: %+v", diag.Description()) - } - switch diag.Description().Detail { - case fmt.Sprintf(errorSummary, "instance"): - rootErr = true - case fmt.Sprintf(errorSummary, "resource"): - subErr = true - default: - t.Errorf("Unexpected error: %s", diag.Description()) - } - } - if !rootErr { - t.Errorf("Expected unsupported provider_meta block error for root module, none received") - } - if !subErr { - t.Errorf("Expected unsupported provider_meta block error for sub-module, none received") - } -} - -func TestContext2Apply_ProviderMeta_refresh_setInvalid(t *testing.T) { - m := testModule(t, "provider-meta-set") - p := testProvider("test") - p.PlanResourceChangeFn = testDiffFn - - // we need a matching schema for plan/apply so they don't error - schema := p.ProviderSchema() - schema.ProviderMeta = &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "baz": { - Type: cty.String, - Required: true, - }, - }, - } - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema) - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - assertNoErrors(t, diags) - - // change the schema before refresh, to test that it errors - schema.ProviderMeta = &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "quux": { - Type: cty.String, - Required: true, - }, - }, - } - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema) - ctx = testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - _, diags = ctx.Refresh(m, state, DefaultPlanOpts) - if !diags.HasErrors() { - t.Fatalf("refresh supposed to error, has no errors") - } - - var reqErr, invalidErr bool - for _, diag := range diags { - switch diag.Description().Summary { - case "Missing required argument": - if diag.Description().Detail == `The argument "quux" is required, but no definition was found.` { - reqErr = true - } else { - t.Errorf("Unexpected error %+v", diag.Description()) - } - case "Unsupported argument": - if diag.Description().Detail == `An argument named "baz" is not expected here.` { - invalidErr = true - } else { - t.Errorf("Unexpected error %+v", diag.Description()) - } - default: - t.Errorf("Unexpected error %+v", diag.Description()) - } - } - if !reqErr { - t.Errorf("Expected missing required argument error, none received") - } - if !invalidErr { - t.Errorf("Expected unsupported argument error, none received") - } -} - -func TestContext2Apply_ProviderMeta_refreshdata_set(t *testing.T) { - m := testModule(t, "provider-meta-data-set") - p := testProvider("test") - p.PlanResourceChangeFn = testDiffFn - schema := p.ProviderSchema() - schema.ProviderMeta = &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "baz": { - Type: cty.String, - Required: true, - }, - }, - } - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema) - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - rdsPMs := map[string]cty.Value{} - p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse { - rdsPMs[req.TypeName] = req.ProviderMeta - switch req.TypeName { - case "test_data_source": - log.Printf("[TRACE] test_data_source RDSR returning") - return providers.ReadDataSourceResponse{ - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("yo"), - "foo": cty.StringVal("bar"), - }), - } - case "test_file": - log.Printf("[TRACE] test_file RDSR returning") - return providers.ReadDataSourceResponse{ - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("bar"), - "rendered": cty.StringVal("baz"), - "template": cty.StringVal(""), - }), - } - default: - // config drift, oops - log.Printf("[TRACE] unknown request TypeName: %q", req.TypeName) - return providers.ReadDataSourceResponse{} - } - } - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - assertNoErrors(t, diags) - - _, diags = ctx.Refresh(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - if !p.ReadDataSourceCalled { - t.Fatalf("ReadDataSource not called") - } - - expectations := map[string]cty.Value{} - - if pm, ok := rdsPMs["test_file"]; !ok { - t.Fatalf("sub-module ReadDataSource not called") - } else if pm.IsNull() { - t.Fatalf("null ProviderMeta in sub-module ReadDataSource") - } else { - expectations["quux-submodule"] = pm - } - - if pm, ok := rdsPMs["test_data_source"]; !ok { - t.Fatalf("root module ReadDataSource not called") - } else if pm.IsNull() { - t.Fatalf("null ProviderMeta in root module ReadDataSource") - } else { - expectations["quux"] = pm - } - - type metaStruct struct { - Baz string `cty:"baz"` - } - - for expected, v := range expectations { - var meta metaStruct - err := gocty.FromCtyValue(v, &meta) - if err != nil { - t.Fatalf("Error parsing cty value: %s", err) - } - if meta.Baz != expected { - t.Fatalf("Expected meta.Baz to be %q, got %q", expected, meta.Baz) - } - } -} - -func TestContext2Apply_ProviderMeta_refreshdata_unset(t *testing.T) { - m := testModule(t, "provider-meta-data-unset") - p := testProvider("test") - p.PlanResourceChangeFn = testDiffFn - schema := p.ProviderSchema() - schema.ProviderMeta = &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "baz": { - Type: cty.String, - Required: true, - }, - }, - } - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema) - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - rdsPMs := map[string]cty.Value{} - p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse { - rdsPMs[req.TypeName] = req.ProviderMeta - switch req.TypeName { - case "test_data_source": - return providers.ReadDataSourceResponse{ - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("yo"), - "foo": cty.StringVal("bar"), - }), - } - case "test_file": - return providers.ReadDataSourceResponse{ - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("bar"), - "rendered": cty.StringVal("baz"), - "template": cty.StringVal(""), - }), - } - default: - // config drift, oops - return providers.ReadDataSourceResponse{} - } - } - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - _, diags = ctx.Apply(plan, m) - assertNoErrors(t, diags) - - if !p.ReadDataSourceCalled { - t.Fatalf("ReadDataSource not called") - } - - if pm, ok := rdsPMs["test_file"]; !ok { - t.Fatalf("sub-module ReadDataSource not called") - } else if !pm.IsNull() { - t.Fatalf("non-null ProviderMeta in sub-module ReadDataSource") - } - - if pm, ok := rdsPMs["test_data_source"]; !ok { - t.Fatalf("root module ReadDataSource not called") - } else if !pm.IsNull() { - t.Fatalf("non-null ProviderMeta in root module ReadDataSource") - } -} - -func TestContext2Apply_ProviderMeta_refreshdata_setNoSchema(t *testing.T) { - m := testModule(t, "provider-meta-data-set") - p := testProvider("test") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{ - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("yo"), - "foo": cty.StringVal("bar"), - }), - } - - _, diags := ctx.Refresh(m, states.NewState(), DefaultPlanOpts) - if !diags.HasErrors() { - t.Fatalf("refresh supposed to error, has no errors") - } - - var rootErr, subErr bool - errorSummary := "The resource data.test_%s.foo belongs to a provider that doesn't support provider_meta blocks" - for _, diag := range diags { - if diag.Description().Summary != "Provider registry.terraform.io/hashicorp/test doesn't support provider_meta" { - t.Errorf("Unexpected error: %+v", diag.Description()) - } - switch diag.Description().Detail { - case fmt.Sprintf(errorSummary, "data_source"): - rootErr = true - case fmt.Sprintf(errorSummary, "file"): - subErr = true - default: - t.Errorf("Unexpected error: %s", diag.Description()) - } - } - if !rootErr { - t.Errorf("Expected unsupported provider_meta block error for root module, none received") - } - if !subErr { - t.Errorf("Expected unsupported provider_meta block error for sub-module, none received") - } -} - -func TestContext2Apply_ProviderMeta_refreshdata_setInvalid(t *testing.T) { - m := testModule(t, "provider-meta-data-set") - p := testProvider("test") - p.PlanResourceChangeFn = testDiffFn - schema := p.ProviderSchema() - schema.ProviderMeta = &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "quux": { - Type: cty.String, - Required: true, - }, - }, - } - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema) - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{ - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("yo"), - "foo": cty.StringVal("bar"), - }), - } - - _, diags := ctx.Refresh(m, states.NewState(), DefaultPlanOpts) - if !diags.HasErrors() { - t.Fatalf("refresh supposed to error, has no errors") - } - - var reqErr, invalidErr bool - for _, diag := range diags { - switch diag.Description().Summary { - case "Missing required argument": - if diag.Description().Detail == `The argument "quux" is required, but no definition was found.` { - reqErr = true - } else { - t.Errorf("Unexpected error %+v", diag.Description()) - } - case "Unsupported argument": - if diag.Description().Detail == `An argument named "baz" is not expected here.` { - invalidErr = true - } else { - t.Errorf("Unexpected error %+v", diag.Description()) - } - default: - t.Errorf("Unexpected error %+v", diag.Description()) - } - } - if !reqErr { - t.Errorf("Expected missing required argument error, none received") - } - if !invalidErr { - t.Errorf("Expected unsupported argument error, none received") - } -} - -func TestContext2Apply_expandModuleVariables(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -module "mod1" { - for_each = toset(["a"]) - source = "./mod" -} - -module "mod2" { - source = "./mod" - in = module.mod1["a"].out -} -`, - "mod/main.tf": ` -resource "aws_instance" "foo" { - foo = var.in -} - -variable "in" { - type = string - default = "default" -} - -output "out" { - value = aws_instance.foo.id -} -`, - }) - - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - - expected := ` -module.mod1["a"]: - aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = default - type = aws_instance - - Outputs: - - out = foo -module.mod2: - aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = foo - type = aws_instance - - Dependencies: - module.mod1.aws_instance.foo` - - if state.String() != expected { - t.Fatalf("expected:\n%s\ngot:\n%s\n", expected, state) - } -} - -func TestContext2Apply_inheritAndStoreCBD(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "aws_instance" "foo" { -} - -resource "aws_instance" "cbd" { - foo = aws_instance.foo.id - lifecycle { - create_before_destroy = true - } -} -`, - }) - - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - - foo := state.ResourceInstance(mustResourceInstanceAddr("aws_instance.foo")) - if !foo.Current.CreateBeforeDestroy { - t.Fatal("aws_instance.foo should also be create_before_destroy") - } -} - -func TestContext2Apply_moduleDependsOn(t *testing.T) { - m := testModule(t, "apply-module-depends-on") - - p := testProvider("test") - - // each instance being applied should happen in sequential order - applied := int64(0) - - p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse { - cfg := req.Config.AsValueMap() - foo := cfg["foo"].AsString() - ord := atomic.LoadInt64(&applied) - - resp := providers.ReadDataSourceResponse{ - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("data"), - "foo": cfg["foo"], - }), - } - - if foo == "a" && ord < 4 { - // due to data source "a"'s module depending on instance 4, this - // should not be less than 4 - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("data source a read too early")) - } - if foo == "b" && ord < 1 { - // due to data source "b"'s module depending on instance 1, this - // should not be less than 1 - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("data source b read too early")) - } - return resp - } - p.PlanResourceChangeFn = testDiffFn - - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - state := req.PlannedState.AsValueMap() - num, _ := state["num"].AsBigFloat().Float64() - ord := int64(num) - if !atomic.CompareAndSwapInt64(&applied, ord-1, ord) { - actual := atomic.LoadInt64(&applied) - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("instance %d was applied after %d", ord, actual)) - } - - state["id"] = cty.StringVal(fmt.Sprintf("test_%d", ord)) - state["type"] = cty.StringVal("test_instance") - resp.NewState = cty.ObjectVal(state) - - return resp - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - - plan, diags = ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - - for _, res := range plan.Changes.Resources { - if res.Action != plans.NoOp { - t.Fatalf("expected NoOp, got %s for %s", res.Action, res.Addr) - } - } -} - -func TestContext2Apply_moduleSelfReference(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -module "test" { - source = "./test" - - a = module.test.b -} - -output "c" { - value = module.test.c -} -`, - "test/main.tf": ` -variable "a" {} - -resource "test_instance" "test" { -} - -output "b" { - value = test_instance.test.id -} - -output "c" { - value = var.a -}`}) - - p := testProvider("test") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - - ctx = testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags = ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - - if !state.Empty() { - t.Fatal("expected empty state, got:", state) - } -} - -func TestContext2Apply_moduleExpandDependsOn(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -module "child" { - count = 1 - source = "./child" - - depends_on = [test_instance.a, test_instance.b] -} - -resource "test_instance" "a" { -} - - -resource "test_instance" "b" { -} -`, - "child/main.tf": ` -resource "test_instance" "foo" { -} - -output "myoutput" { - value = "literal string" -} -`}) - - p := testProvider("test") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - - ctx = testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags = ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - - if !state.Empty() { - t.Fatal("expected empty state, got:", state) - } -} - -func TestContext2Apply_scaleInCBD(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -variable "ct" { - type = number -} - -resource "test_instance" "a" { - count = var.ct -} - -resource "test_instance" "b" { - require_new = local.removable - lifecycle { - create_before_destroy = true - } -} - -resource "test_instance" "c" { - require_new = test_instance.b.id - lifecycle { - create_before_destroy = true - } -} - -output "out" { - value = join(".", test_instance.a[*].id) -} - -locals { - removable = join(".", test_instance.a[*].id) -} -`}) - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_instance.a[0]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"a0"}`), - Dependencies: []addrs.ConfigResource{}, - CreateBeforeDestroy: true, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_instance.a[1]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"a1"}`), - Dependencies: []addrs.ConfigResource{}, - CreateBeforeDestroy: true, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_instance.b").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"b", "require_new":"old.old"}`), - Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_instance.a")}, - CreateBeforeDestroy: true, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_instance.c").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"c", "require_new":"b"}`), - Dependencies: []addrs.ConfigResource{ - mustConfigResourceAddr("test_instance.a"), - mustConfigResourceAddr("test_instance.b"), - }, - CreateBeforeDestroy: true, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - p := testProvider("test") - - p.PlanResourceChangeFn = func(r providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { - // this is a destroy plan - if r.ProposedNewState.IsNull() { - resp.PlannedState = r.ProposedNewState - resp.PlannedPrivate = r.PriorPrivate - return resp - } - - n := r.ProposedNewState.AsValueMap() - - if r.PriorState.IsNull() { - n["id"] = cty.UnknownVal(cty.String) - resp.PlannedState = cty.ObjectVal(n) - return resp - } - - p := r.PriorState.AsValueMap() - - priorRN := p["require_new"] - newRN := n["require_new"] - - if eq := priorRN.Equals(newRN); !eq.IsKnown() || eq.False() { - resp.RequiresReplace = []cty.Path{{cty.GetAttrStep{Name: "require_new"}}} - n["id"] = cty.UnknownVal(cty.String) - } - - resp.PlannedState = cty.ObjectVal(n) - return resp - } - - // reduce the count to 1 - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "ct": &InputValue{ - Value: cty.NumberIntVal(1), - SourceType: ValueFromCaller, - }, - }, - }) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - { - addr := mustResourceInstanceAddr("test_instance.a[0]") - change := plan.Changes.ResourceInstance(addr) - if change == nil { - t.Fatalf("no planned change for %s", addr) - } - if got, want := change.PrevRunAddr, mustResourceInstanceAddr("test_instance.a[0]"); !want.Equal(got) { - t.Errorf("wrong previous run address for %s %s; want %s", addr, got, want) - } - if got, want := change.Action, plans.NoOp; got != want { - t.Errorf("wrong action for %s %s; want %s", addr, got, want) - } - if got, want := change.ActionReason, plans.ResourceInstanceChangeNoReason; got != want { - t.Errorf("wrong action reason for %s %s; want %s", addr, got, want) - } - } - { - addr := mustResourceInstanceAddr("test_instance.a[1]") - change := plan.Changes.ResourceInstance(addr) - if change == nil { - t.Fatalf("no planned change for %s", addr) - } - if got, want := change.PrevRunAddr, mustResourceInstanceAddr("test_instance.a[1]"); !want.Equal(got) { - t.Errorf("wrong previous run address for %s %s; want %s", addr, got, want) - } - if got, want := change.Action, plans.Delete; got != want { - t.Errorf("wrong action for %s %s; want %s", addr, got, want) - } - if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseCountIndex; got != want { - t.Errorf("wrong action reason for %s %s; want %s", addr, got, want) - } - } - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - log.Fatal(diags.ErrWithWarnings()) - } - - // check the output, as those can't cause an error planning the value - out := state.RootModule().OutputValues["out"].Value.AsString() - if out != "a0" { - t.Fatalf(`expected output "a0", got: %q`, out) - } - - // reduce the count to 0 - ctx = testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags = ctx.Plan(m, state, &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "ct": &InputValue{ - Value: cty.NumberIntVal(0), - SourceType: ValueFromCaller, - }, - }, - }) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - { - addr := mustResourceInstanceAddr("test_instance.a[0]") - change := plan.Changes.ResourceInstance(addr) - if change == nil { - t.Fatalf("no planned change for %s", addr) - } - if got, want := change.PrevRunAddr, mustResourceInstanceAddr("test_instance.a[0]"); !want.Equal(got) { - t.Errorf("wrong previous run address for %s %s; want %s", addr, got, want) - } - if got, want := change.Action, plans.Delete; got != want { - t.Errorf("wrong action for %s %s; want %s", addr, got, want) - } - if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseCountIndex; got != want { - t.Errorf("wrong action reason for %s %s; want %s", addr, got, want) - } - } - { - addr := mustResourceInstanceAddr("test_instance.a[1]") - change := plan.Changes.ResourceInstance(addr) - if change != nil { - // It was already removed in the previous plan/apply - t.Errorf("unexpected planned change for %s", addr) - } - } - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - - // check the output, as those can't cause an error planning the value - out = state.RootModule().OutputValues["out"].Value.AsString() - if out != "" { - t.Fatalf(`expected output "", got: %q`, out) - } -} - -// Ensure that we can destroy when a provider references a resource that will -// also be destroyed -func TestContext2Apply_destroyProviderReference(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -provider "null" { - value = "" -} - -module "mod" { - source = "./mod" -} - -provider "test" { - value = module.mod.output -} - -resource "test_instance" "bar" { -} -`, - "mod/main.tf": ` -data "null_data_source" "foo" { - count = 1 -} - - -output "output" { - value = data.null_data_source.foo[0].output -} -`}) - - schemaFn := func(name string) *ProviderSchema { - return &ProviderSchema{ - Provider: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "value": { - Type: cty.String, - Required: true, - }, - }, - }, - ResourceTypes: map[string]*configschema.Block{ - name + "_instance": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - "foo": { - Type: cty.String, - Optional: true, - }, - }, - }, - }, - DataSources: map[string]*configschema.Block{ - name + "_data_source": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - "output": { - Type: cty.String, - Computed: true, - }, - }, - }, - }, - } - } - - testP := new(MockProvider) - testP.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse { - return providers.ReadResourceResponse{NewState: req.PriorState} - } - testP.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schemaFn("test")) - - providerConfig := "" - testP.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) { - value := req.Config.GetAttr("value") - if value.IsKnown() && !value.IsNull() { - providerConfig = value.AsString() - } else { - providerConfig = "" - } - return resp - } - testP.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - if providerConfig != "valid" { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provider config is %q", providerConfig)) - return - } - return testApplyFn(req) - } - testP.PlanResourceChangeFn = testDiffFn - - nullP := new(MockProvider) - nullP.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse { - return providers.ReadResourceResponse{NewState: req.PriorState} - } - nullP.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schemaFn("null")) - - nullP.ApplyResourceChangeFn = testApplyFn - nullP.PlanResourceChangeFn = testDiffFn - - nullP.ReadDataSourceResponse = &providers.ReadDataSourceResponse{ - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("ID"), - "output": cty.StringVal("valid"), - }), - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(testP), - addrs.NewDefaultProvider("null"): testProviderFuncFixed(nullP), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } - - ctx = testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(testP), - addrs.NewDefaultProvider("null"): testProviderFuncFixed(nullP), - }, - }) - - plan, diags = ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - assertNoErrors(t, diags) - - if _, diags := ctx.Apply(plan, m); diags.HasErrors() { - t.Fatalf("destroy apply errors: %s", diags.Err()) - } -} - -// Destroying properly requires pruning out all unneeded config nodes to -// prevent incorrect expansion evaluation. -func TestContext2Apply_destroyInterModuleExpansion(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -data "test_data_source" "a" { - for_each = { - one = "thing" - } -} - -locals { - module_input = { - for k, v in data.test_data_source.a : k => v.id - } -} - -module "mod1" { - source = "./mod" - input = local.module_input -} - -module "mod2" { - source = "./mod" - input = module.mod1.outputs -} - -resource "test_instance" "bar" { - for_each = module.mod2.outputs -} - -output "module_output" { - value = module.mod2.outputs -} -output "test_instances" { - value = test_instance.bar -} -`, - "mod/main.tf": ` -variable "input" { -} - -data "test_data_source" "foo" { - for_each = var.input -} - -output "outputs" { - value = data.test_data_source.foo -} -`}) - - p := testProvider("test") - p.PlanResourceChangeFn = testDiffFn - p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse { - return providers.ReadDataSourceResponse{ - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("data_source"), - "foo": cty.StringVal("output"), - }), - } - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } - - destroy := func() { - ctx = testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags = ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - assertNoErrors(t, diags) - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("destroy apply errors: %s", diags.Err()) - } - } - - destroy() - // Destroying again from the empty state should not cause any errors either - destroy() -} - -func TestContext2Apply_createBeforeDestroyWithModule(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -variable "v" {} - -module "mod" { - source = "./mod" - in = var.v -} - -resource "test_resource" "a" { - value = var.v - depends_on = [module.mod] - lifecycle { - create_before_destroy = true - } -} -`, - "mod/main.tf": ` -variable "in" {} - -resource "test_resource" "a" { - value = var.in -} -`}) - - p := testProvider("test") - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { - // this is a destroy plan - if req.ProposedNewState.IsNull() { - resp.PlannedState = req.ProposedNewState - resp.PlannedPrivate = req.PriorPrivate - return resp - } - - proposed := req.ProposedNewState.AsValueMap() - proposed["id"] = cty.UnknownVal(cty.String) - - resp.PlannedState = cty.ObjectVal(proposed) - resp.RequiresReplace = []cty.Path{{cty.GetAttrStep{Name: "value"}}} - return resp - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "v": &InputValue{ - Value: cty.StringVal("A"), - }, - }, - }) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } - - ctx = testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags = ctx.Plan(m, state, &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "v": &InputValue{ - Value: cty.StringVal("B"), - }, - }, - }) - assertNoErrors(t, diags) - - _, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } -} - -func TestContext2Apply_forcedCBD(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -variable "v" {} - -resource "test_instance" "a" { - require_new = var.v -} - -resource "test_instance" "b" { - depends_on = [test_instance.a] - lifecycle { - create_before_destroy = true - } -} -`}) - - p := testProvider("test") - p.PlanResourceChangeFn = testDiffFn - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "v": &InputValue{ - Value: cty.StringVal("A"), - }, - }, - }) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } - - ctx = testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags = ctx.Plan(m, state, &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "v": &InputValue{ - Value: cty.StringVal("B"), - }, - }, - }) - assertNoErrors(t, diags) - - _, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } -} - -func TestContext2Apply_removeReferencedResource(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -variable "ct" { -} - -resource "test_resource" "to_remove" { - count = var.ct -} - -resource "test_resource" "c" { - value = join("", test_resource.to_remove[*].id) -} -`}) - - p := testProvider("test") - p.PlanResourceChangeFn = testDiffFn - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "ct": &InputValue{ - Value: cty.NumberIntVal(1), - }, - }, - }) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } - - ctx = testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags = ctx.Plan(m, state, &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "ct": &InputValue{ - Value: cty.NumberIntVal(0), - }, - }, - }) - assertNoErrors(t, diags) - - _, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } -} - -func TestContext2Apply_variableSensitivity(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -variable "sensitive_var" { - default = "foo" - sensitive = true -} - -variable "sensitive_id" { - default = "secret id" - sensitive = true -} - -resource "test_resource" "foo" { - value = var.sensitive_var - - network_interface { - network_interface_id = var.sensitive_id - } -}`, - }) - - p := new(MockProvider) - p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse { - return providers.ReadResourceResponse{NewState: req.PriorState} - } - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - Provider: &configschema.Block{}, - ResourceTypes: map[string]*configschema.Block{ - "test_resource": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - "value": { - Type: cty.String, - Optional: true, - Computed: true, - }, - }, - BlockTypes: map[string]*configschema.NestedBlock{ - "network_interface": { - Block: configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "network_interface_id": {Type: cty.String, Optional: true}, - "device_index": {Type: cty.Number, Optional: true}, - }, - }, - Nesting: configschema.NestingSet, - }, - }, - }, - }, - }) - p.PlanResourceChangeFn = testDiffFn - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } - - // Run a second apply with no changes - ctx = testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags = ctx.Plan(m, state, SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))) - assertNoErrors(t, diags) - - state, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } - - // Now change the variable value for sensitive_var - ctx = testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags = ctx.Plan(m, state, &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "sensitive_id": &InputValue{Value: cty.NilVal}, - "sensitive_var": &InputValue{ - Value: cty.StringVal("bar"), - }, - }, - }) - assertNoErrors(t, diags) - - _, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } -} - -func TestContext2Apply_variableSensitivityPropagation(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -variable "sensitive_map" { - type = map(string) - default = { - "x" = "foo" - } - sensitive = true -} - -resource "test_resource" "foo" { - value = var.sensitive_map.x -} -`, - }) - - p := testProvider("test") - p.PlanResourceChangeFn = testDiffFn - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))) - if diags.HasErrors() { - t.Fatalf("plan errors: %s", diags.Err()) - } - - verifySensitiveValue := func(pvms []cty.PathValueMarks) { - if len(pvms) != 1 { - t.Fatalf("expected 1 sensitive path, got %d", len(pvms)) - } - pvm := pvms[0] - if gotPath, wantPath := pvm.Path, cty.GetAttrPath("value"); !gotPath.Equals(wantPath) { - t.Errorf("wrong path\n got: %#v\nwant: %#v", gotPath, wantPath) - } - if gotMarks, wantMarks := pvm.Marks, cty.NewValueMarks(marks.Sensitive); !gotMarks.Equal(wantMarks) { - t.Errorf("wrong marks\n got: %#v\nwant: %#v", gotMarks, wantMarks) - } - } - - addr := mustResourceInstanceAddr("test_resource.foo") - fooChangeSrc := plan.Changes.ResourceInstance(addr) - verifySensitiveValue(fooChangeSrc.AfterValMarks) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } - - fooState := state.ResourceInstance(addr) - verifySensitiveValue(fooState.Current.AttrSensitivePaths) -} - -func TestContext2Apply_variableSensitivityProviders(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "test_resource" "foo" { - sensitive_value = "should get marked" -} - -resource "test_resource" "bar" { - value = test_resource.foo.sensitive_value - random = test_resource.foo.id # not sensitive - - nesting_single { - value = "abc" - sensitive_value = "xyz" - } -} - -resource "test_resource" "baz" { - value = test_resource.bar.nesting_single.sensitive_value -} -`, - }) - - p := testProvider("test") - p.PlanResourceChangeFn = testDiffFn - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("plan errors: %s", diags.Err()) - } - - verifySensitiveValue := func(pvms []cty.PathValueMarks) { - if len(pvms) != 1 { - t.Fatalf("expected 1 sensitive path, got %d", len(pvms)) - } - pvm := pvms[0] - if gotPath, wantPath := pvm.Path, cty.GetAttrPath("value"); !gotPath.Equals(wantPath) { - t.Errorf("wrong path\n got: %#v\nwant: %#v", gotPath, wantPath) - } - if gotMarks, wantMarks := pvm.Marks, cty.NewValueMarks(marks.Sensitive); !gotMarks.Equal(wantMarks) { - t.Errorf("wrong marks\n got: %#v\nwant: %#v", gotMarks, wantMarks) - } - } - - // Sensitive attributes (defined by the provider) are marked - // as sensitive when referenced from another resource - // "bar" references sensitive resources in "foo" - barAddr := mustResourceInstanceAddr("test_resource.bar") - barChangeSrc := plan.Changes.ResourceInstance(barAddr) - verifySensitiveValue(barChangeSrc.AfterValMarks) - - bazAddr := mustResourceInstanceAddr("test_resource.baz") - bazChangeSrc := plan.Changes.ResourceInstance(bazAddr) - verifySensitiveValue(bazChangeSrc.AfterValMarks) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } - - barState := state.ResourceInstance(barAddr) - verifySensitiveValue(barState.Current.AttrSensitivePaths) - - bazState := state.ResourceInstance(bazAddr) - verifySensitiveValue(bazState.Current.AttrSensitivePaths) -} - -func TestContext2Apply_variableSensitivityChange(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -variable "sensitive_var" { - default = "hello" - sensitive = true -} - -resource "test_resource" "foo" { - value = var.sensitive_var -}`, - }) - - p := testProvider("test") - p.PlanResourceChangeFn = testDiffFn - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - state := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_resource", - Name: "foo", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo", "value":"hello"}`), - // No AttrSensitivePaths present - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("test"), - Module: addrs.RootModule, - }, - ) - }) - - plan, diags := ctx.Plan(m, state, SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))) - assertNoErrors(t, diags) - - addr := mustResourceInstanceAddr("test_resource.foo") - - state, diags = ctx.Apply(plan, m) - assertNoErrors(t, diags) - - fooState := state.ResourceInstance(addr) - - if len(fooState.Current.AttrSensitivePaths) != 1 { - t.Fatalf("wrong number of sensitive paths, expected 1, got, %v", len(fooState.Current.AttrSensitivePaths)) - } - got := fooState.Current.AttrSensitivePaths[0] - want := cty.PathValueMarks{ - Path: cty.GetAttrPath("value"), - Marks: cty.NewValueMarks(marks.Sensitive), - } - - if !got.Equal(want) { - t.Fatalf("wrong value marks; got:\n%#v\n\nwant:\n%#v\n", got, want) - } - - m2 := testModuleInline(t, map[string]string{ - "main.tf": ` -variable "sensitive_var" { - default = "hello" - sensitive = false -} - -resource "test_resource" "foo" { - value = var.sensitive_var -}`, - }) - - ctx2 := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - // NOTE: Prior to our refactoring to make the state an explicit argument - // of Plan, as opposed to hidden state inside Context, this test was - // calling ctx.Apply instead of ctx2.Apply and thus using the previous - // plan instead of this new plan. "Fixing" it to use the new plan seems - // to break the test, so we've preserved that oddity here by saving the - // old plan as oldPlan and essentially discarding the new plan entirely, - // but this seems rather suspicious and we should ideally figure out what - // this test was originally intending to do and make it do that. - oldPlan := plan - _, diags = ctx2.Plan(m2, state, SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))) - assertNoErrors(t, diags) - stateWithoutSensitive, diags := ctx.Apply(oldPlan, m) - assertNoErrors(t, diags) - - fooState2 := stateWithoutSensitive.ResourceInstance(addr) - if len(fooState2.Current.AttrSensitivePaths) > 0 { - t.Fatalf( - "wrong number of sensitive paths, expected 0, got, %v\n%s", - len(fooState2.Current.AttrSensitivePaths), - spew.Sdump(fooState2.Current.AttrSensitivePaths), - ) - } -} - -func TestContext2Apply_moduleVariableOptionalAttributes(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -variable "in" { - type = object({ - required = string - optional = optional(string) - default = optional(bool, true) - nested = optional( - map(object({ - a = optional(string, "foo") - b = optional(number, 5) - })), { - "boop": {} - } - ) - }) -} - -output "out" { - value = var.in -} -`}) - - ctx := testContext2(t, &ContextOpts{}) - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "in": &InputValue{ - Value: cty.MapVal(map[string]cty.Value{ - "required": cty.StringVal("boop"), - }), - SourceType: ValueFromCaller, - }, - }, - }) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - - got := state.RootModule().OutputValues["out"].Value - want := cty.ObjectVal(map[string]cty.Value{ - "required": cty.StringVal("boop"), - - // Because "optional" was marked as optional, it got silently filled - // in as a null value of string type rather than returning an error. - "optional": cty.NullVal(cty.String), - - // Similarly, "default" was marked as optional with a default value, - // and since it was omitted should be filled in with that default. - "default": cty.True, - - // Nested is a complex structure which has fully described defaults, - // so again it should be filled with the default structure. - "nested": cty.MapVal(map[string]cty.Value{ - "boop": cty.ObjectVal(map[string]cty.Value{ - "a": cty.StringVal("foo"), - "b": cty.NumberIntVal(5), - }), - }), - }) - if !want.RawEquals(got) { - t.Fatalf("wrong result\ngot: %#v\nwant: %#v", got, want) - } -} - -func TestContext2Apply_moduleVariableOptionalAttributesDefault(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -variable "in" { - type = object({ - required = string - optional = optional(string) - default = optional(bool, true) - }) - default = { - required = "boop" - } -} - -output "out" { - value = var.in -} -`}) - - ctx := testContext2(t, &ContextOpts{}) - - // We don't specify a value for the variable here, relying on its defined - // default. - plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - - got := state.RootModule().OutputValues["out"].Value - want := cty.ObjectVal(map[string]cty.Value{ - "required": cty.StringVal("boop"), - - // "optional" is not present in the variable default, so it is filled - // with null. - "optional": cty.NullVal(cty.String), - - // Similarly, "default" is not present in the variable default, so its - // value is replaced with the type's specified default. - "default": cty.True, - }) - if !want.RawEquals(got) { - t.Fatalf("wrong result\ngot: %#v\nwant: %#v", got, want) - } -} - -func TestContext2Apply_moduleVariableOptionalAttributesDefaultNull(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -variable "in" { - type = object({ - required = string - optional = optional(string) - default = optional(bool, true) - }) - default = null -} - -# Wrap the input variable in a tuple because a null output value is elided from -# the plan, which prevents us from testing its type. -output "out" { - value = [var.in] -} -`}) - - ctx := testContext2(t, &ContextOpts{}) - - // We don't specify a value for the variable here, relying on its defined - // default. - plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - - got := state.RootModule().OutputValues["out"].Value - // The null default value should be bound, after type converting to the - // full object type - want := cty.TupleVal([]cty.Value{cty.NullVal(cty.Object(map[string]cty.Type{ - "required": cty.String, - "optional": cty.String, - "default": cty.Bool, - }))}) - if !want.RawEquals(got) { - t.Fatalf("wrong result\ngot: %#v\nwant: %#v", got, want) - } -} - -func TestContext2Apply_moduleVariableOptionalAttributesDefaultChild(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -variable "in" { - type = list(object({ - a = optional(set(string)) - })) - default = [ - { a = [ "foo" ] }, - { }, - ] -} - -module "child" { - source = "./child" - in = var.in -} - -output "out" { - value = module.child.out -} -`, - "child/main.tf": ` -variable "in" { - type = list(object({ - a = optional(set(string), []) - })) - default = [] -} - -output "out" { - value = var.in -} -`, - }) - - ctx := testContext2(t, &ContextOpts{}) - - // We don't specify a value for the variable here, relying on its defined - // default. - plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - - got := state.RootModule().OutputValues["out"].Value - want := cty.ListVal([]cty.Value{ - cty.ObjectVal(map[string]cty.Value{ - "a": cty.SetVal([]cty.Value{cty.StringVal("foo")}), - }), - cty.ObjectVal(map[string]cty.Value{ - "a": cty.SetValEmpty(cty.String), - }), - }) - if !want.RawEquals(got) { - t.Fatalf("wrong result\ngot: %#v\nwant: %#v", got, want) - } -} - -func TestContext2Apply_provisionerSensitive(t *testing.T) { - m := testModule(t, "apply-provisioner-sensitive") - p := testProvider("aws") - - pr := testProvisioner() - pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) { - if req.Config.ContainsMarked() { - t.Fatalf("unexpectedly marked config value: %#v", req.Config) - } - command := req.Config.GetAttr("command") - if command.IsMarked() { - t.Fatalf("unexpectedly marked command argument: %#v", command.Marks()) - } - req.UIOutput.Output(fmt.Sprintf("Executing: %q", command.AsString())) - return - } - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = testApplyFn - - h := new(MockHook) - ctx := testContext2(t, &ContextOpts{ - Hooks: []Hook{h}, - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Provisioners: map[string]provisioners.Factory{ - "shell": testProvisionerFuncFixed(pr), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "password": &InputValue{ - Value: cty.StringVal("secret"), - SourceType: ValueFromCaller, - }, - }, - }) - assertNoErrors(t, diags) - - // "restart" provisioner - pr.CloseCalled = false - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - logDiagnostics(t, diags) - t.Fatal("apply failed") - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testTerraformApplyProvisionerSensitiveStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } - - // Verify apply was invoked - if !pr.ProvisionResourceCalled { - t.Fatalf("provisioner was not called on apply") - } - - // Verify output was suppressed - if !h.ProvisionOutputCalled { - t.Fatalf("ProvisionOutput hook not called") - } - if got, doNotWant := h.ProvisionOutputMessage, "secret"; strings.Contains(got, doNotWant) { - t.Errorf("sensitive value %q included in output:\n%s", doNotWant, got) - } - if got, want := h.ProvisionOutputMessage, "output suppressed"; !strings.Contains(got, want) { - t.Errorf("expected hook to be called with %q, but was:\n%s", want, got) - } -} - -func TestContext2Apply_warnings(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "test_resource" "foo" { -}`, - }) - - p := testProvider("test") - p.PlanResourceChangeFn = testDiffFn - - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse { - resp := testApplyFn(req) - - resp.Diagnostics = resp.Diagnostics.Append(tfdiags.SimpleWarning("warning")) - return resp - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - state, diags := ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } - - inst := state.ResourceInstance(mustResourceInstanceAddr("test_resource.foo")) - if inst == nil { - t.Fatal("missing 'test_resource.foo' in state:", state) - } -} - -func TestContext2Apply_rpcDiagnostics(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "test_instance" "a" { -} -`, - }) - - p := testProvider("test") - p.PlanResourceChangeFn = testDiffFn - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - resp = testApplyFn(req) - resp.Diagnostics = resp.Diagnostics.Append(tfdiags.SimpleWarning("don't frobble")) - return resp - } - - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test_instance": { - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Computed: true}, - }, - }, - }, - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatal(diags.Err()) - } - - _, diags = ctx.Apply(plan, m) - if diags.HasErrors() { - t.Fatal(diags.Err()) - } - - if len(diags) == 0 { - t.Fatal("expected warnings") - } - - for _, d := range diags { - des := d.Description().Summary - if !strings.Contains(des, "frobble") { - t.Fatalf(`expected frobble, got %q`, des) - } - } -} - -func TestContext2Apply_dataSensitive(t *testing.T) { - m := testModule(t, "apply-data-sensitive") - p := testProvider("null") - p.PlanResourceChangeFn = testDiffFn - p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse { - // add the required id - m := req.Config.AsValueMap() - m["id"] = cty.StringVal("foo") - - return providers.ReadDataSourceResponse{ - State: cty.ObjectVal(m), - } - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("null"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))) - if diags.HasErrors() { - t.Fatalf("diags: %s", diags.Err()) - } else { - t.Logf(legacyDiffComparisonString(plan.Changes)) - } - - state, diags := ctx.Apply(plan, m) - assertNoErrors(t, diags) - - addr := mustResourceInstanceAddr("data.null_data_source.testing") - - dataSourceState := state.ResourceInstance(addr) - pvms := dataSourceState.Current.AttrSensitivePaths - if len(pvms) != 1 { - t.Fatalf("expected 1 sensitive path, got %d", len(pvms)) - } - pvm := pvms[0] - if gotPath, wantPath := pvm.Path, cty.GetAttrPath("foo"); !gotPath.Equals(wantPath) { - t.Errorf("wrong path\n got: %#v\nwant: %#v", gotPath, wantPath) - } - if gotMarks, wantMarks := pvm.Marks, cty.NewValueMarks(marks.Sensitive); !gotMarks.Equal(wantMarks) { - t.Errorf("wrong marks\n got: %#v\nwant: %#v", gotMarks, wantMarks) - } -} - -func TestContext2Apply_errorRestorePrivateData(t *testing.T) { - // empty config to remove our resource - m := testModuleInline(t, map[string]string{ - "main.tf": "", - }) - - p := simpleMockProvider() - p.ApplyResourceChangeResponse = &providers.ApplyResourceChangeResponse{ - // we error during apply, which will trigger core to preserve the last - // known state, including private data - Diagnostics: tfdiags.Diagnostics(nil).Append(errors.New("oops")), - } - - addr := mustResourceInstanceAddr("test_object.a") - - state := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo"}`), - Private: []byte("private"), - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`)) - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatal(diags.Err()) - } - - state, _ = ctx.Apply(plan, m) - if string(state.ResourceInstance(addr).Current.Private) != "private" { - t.Fatal("missing private data in state") - } -} - -func TestContext2Apply_errorRestoreStatus(t *testing.T) { - // empty config to remove our resource - m := testModuleInline(t, map[string]string{ - "main.tf": "", - }) - - p := simpleMockProvider() - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - // We error during apply, but return the current object state. - resp.Diagnostics = resp.Diagnostics.Append(errors.New("oops")) - // return a warning too to make sure it isn't dropped - resp.Diagnostics = resp.Diagnostics.Append(tfdiags.SimpleWarning("warned")) - resp.NewState = req.PriorState - resp.Private = req.PlannedPrivate - return resp - } - - addr := mustResourceInstanceAddr("test_object.a") - - state := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{ - Status: states.ObjectTainted, - AttrsJSON: []byte(`{"test_string":"foo"}`), - Private: []byte("private"), - Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.b")}, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`)) - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatal(diags.Err()) - } - - state, diags = ctx.Apply(plan, m) - - errString := diags.ErrWithWarnings().Error() - if !strings.Contains(errString, "oops") || !strings.Contains(errString, "warned") { - t.Fatalf("error missing expected info: %q", errString) - } - - if len(diags) != 2 { - t.Fatalf("expected 1 error and 1 warning, got: %q", errString) - } - - res := state.ResourceInstance(addr) - if res == nil { - t.Fatal("resource was removed from state") - } - - if res.Current.Status != states.ObjectTainted { - t.Fatal("resource should still be tainted in the state") - } - - if len(res.Current.Dependencies) != 1 || !res.Current.Dependencies[0].Equal(mustConfigResourceAddr("test_object.b")) { - t.Fatalf("incorrect dependencies, got %q", res.Current.Dependencies) - } - - if string(res.Current.Private) != "private" { - t.Fatalf("incorrect private data, got %q", res.Current.Private) - } -} - -func TestContext2Apply_nonConformingResponse(t *testing.T) { - // empty config to remove our resource - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "test_object" "a" { - test_string = "x" -} -`, - }) - - p := simpleMockProvider() - respDiags := tfdiags.Diagnostics(nil).Append(tfdiags.SimpleWarning("warned")) - respDiags = respDiags.Append(errors.New("oops")) - p.ApplyResourceChangeResponse = &providers.ApplyResourceChangeResponse{ - // Don't lose these diagnostics - Diagnostics: respDiags, - // This state is missing required attributes, and should produce an error - NewState: cty.ObjectVal(map[string]cty.Value{ - "test_string": cty.StringVal("x"), - }), - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatal(diags.Err()) - } - - _, diags = ctx.Apply(plan, m) - errString := diags.ErrWithWarnings().Error() - if !strings.Contains(errString, "oops") || !strings.Contains(errString, "warned") { - t.Fatalf("error missing expected info: %q", errString) - } - - // we should have more than the ones returned from the provider, and they - // should not be coalesced into a single value - if len(diags) < 3 { - t.Fatalf("incorrect diagnostics, got %d values with %s", len(diags), diags.ErrWithWarnings()) - } -} - -func TestContext2Apply_nilResponse(t *testing.T) { - // empty config to remove our resource - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "test_object" "a" { -} -`, - }) - - p := simpleMockProvider() - p.ApplyResourceChangeResponse = &providers.ApplyResourceChangeResponse{} - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatal(diags.Err()) - } - - _, diags = ctx.Apply(plan, m) - if !diags.HasErrors() { - t.Fatal("expected and error") - } - - errString := diags.ErrWithWarnings().Error() - if !strings.Contains(errString, "invalid nil value") { - t.Fatalf("error missing expected info: %q", errString) - } -} - -//////////////////////////////////////////////////////////////////////////////// -// NOTE: Due to the size of this file, new tests should be added to -// context_apply2_test.go. -//////////////////////////////////////////////////////////////////////////////// diff --git a/internal/terraform/context_eval.go b/internal/terraform/context_eval.go deleted file mode 100644 index f9d0f649338b..000000000000 --- a/internal/terraform/context_eval.go +++ /dev/null @@ -1,96 +0,0 @@ -package terraform - -import ( - "log" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/lang" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -type EvalOpts struct { - SetVariables InputValues -} - -// Eval produces a scope in which expressions can be evaluated for -// the given module path. -// -// This method must first evaluate any ephemeral values (input variables, local -// values, and output values) in the configuration. These ephemeral values are -// not included in the persisted state, so they must be re-computed using other -// values in the state before they can be properly evaluated. The updated -// values are retained in the main state associated with the receiving context. -// -// This function takes no action against remote APIs but it does need access -// to all provider and provisioner instances in order to obtain their schemas -// for type checking. -// -// The result is an evaluation scope that can be used to resolve references -// against the root module. If the returned diagnostics contains errors then -// the returned scope may be nil. If it is not nil then it may still be used -// to attempt expression evaluation or other analysis, but some expressions -// may not behave as expected. -func (c *Context) Eval(config *configs.Config, state *states.State, moduleAddr addrs.ModuleInstance, opts *EvalOpts) (*lang.Scope, tfdiags.Diagnostics) { - // This is intended for external callers such as the "terraform console" - // command. Internally, we create an evaluator in c.walk before walking - // the graph, and create scopes in ContextGraphWalker. - - var diags tfdiags.Diagnostics - defer c.acquireRun("eval")() - - // Start with a copy of state so that we don't affect the instance that - // the caller is holding. - state = state.DeepCopy() - var walker *ContextGraphWalker - - variables := opts.SetVariables - - // By the time we get here, we should have values defined for all of - // the root module variables, even if some of them are "unknown". It's the - // caller's responsibility to have already handled the decoding of these - // from the various ways the CLI allows them to be set and to produce - // user-friendly error messages if they are not all present, and so - // the error message from checkInputVariables should never be seen and - // includes language asking the user to report a bug. - varDiags := checkInputVariables(config.Module.Variables, variables) - diags = diags.Append(varDiags) - - log.Printf("[DEBUG] Building and walking 'eval' graph") - - graph, moreDiags := (&EvalGraphBuilder{ - Config: config, - State: state, - RootVariableValues: variables, - Plugins: c.plugins, - }).Build(addrs.RootModuleInstance) - diags = diags.Append(moreDiags) - if moreDiags.HasErrors() { - return nil, diags - } - - walkOpts := &graphWalkOpts{ - InputState: state, - Config: config, - } - - walker, moreDiags = c.walk(graph, walkEval, walkOpts) - diags = diags.Append(moreDiags) - if walker != nil { - diags = diags.Append(walker.NonFatalDiagnostics) - } else { - // If we skipped walking the graph (due to errors) then we'll just - // use a placeholder graph walker here, which'll refer to the - // unmodified state. - walker = c.graphWalker(walkEval, walkOpts) - } - - // This is a bit weird since we don't normally evaluate outside of - // the context of a walk, but we'll "re-enter" our desired path here - // just to get hold of an EvalContext for it. ContextGraphWalker - // caches its contexts, so we should get hold of the context that was - // previously used for evaluation here, unless we skipped walking. - evalCtx := walker.EnterPath(moduleAddr) - return evalCtx.EvaluationScope(nil, EvalDataForNoInstanceKey), diags -} diff --git a/internal/terraform/context_eval_test.go b/internal/terraform/context_eval_test.go deleted file mode 100644 index ac828dbcc424..000000000000 --- a/internal/terraform/context_eval_test.go +++ /dev/null @@ -1,130 +0,0 @@ -package terraform - -import ( - "testing" - - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" - "github.com/zclconf/go-cty/cty" -) - -func TestContextEval(t *testing.T) { - // This test doesn't check the "Want" value for impure funcs, so the value - // on those doesn't matter. - tests := []struct { - Input string - Want cty.Value - ImpureFunc bool - }{ - { // An impure function: allowed in the console, but the result is nondeterministic - `bcrypt("example")`, - cty.NilVal, - true, - }, - { - `keys(var.map)`, - cty.ListVal([]cty.Value{ - cty.StringVal("foo"), - cty.StringVal("baz"), - }), - true, - }, - { - `local.result`, - cty.NumberIntVal(6), - false, - }, - { - `module.child.result`, - cty.NumberIntVal(6), - false, - }, - } - - // This module has a little bit of everything (and if it is missing somehitng, add to it): - // resources, variables, locals, modules, output - m := testModule(t, "eval-context-basic") - p := testProvider("test") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - scope, diags := ctx.Eval(m, states.NewState(), addrs.RootModuleInstance, &EvalOpts{ - SetVariables: testInputValuesUnset(m.Module.Variables), - }) - if diags.HasErrors() { - t.Fatalf("Eval errors: %s", diags.Err()) - } - - // Since we're testing 'eval' (used by terraform console), impure functions - // should be allowed by the scope. - if scope.PureOnly == true { - t.Fatal("wrong result: eval should allow impure funcs") - } - - for _, test := range tests { - t.Run(test.Input, func(t *testing.T) { - // Parse the test input as an expression - expr, _ := hclsyntax.ParseExpression([]byte(test.Input), "", hcl.Pos{Line: 1, Column: 1}) - got, diags := scope.EvalExpr(expr, cty.DynamicPseudoType) - - if diags.HasErrors() { - t.Fatalf("unexpected error: %s", diags.Err()) - } - - if !test.ImpureFunc { - if !got.RawEquals(test.Want) { - t.Fatalf("wrong result: want %#v, got %#v", test.Want, got) - } - } - }) - } -} - -// ensure that we can execute a console when outputs have preconditions -func TestContextEval_outputsWithPreconditions(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -module "mod" { - source = "./mod" - input = "ok" -} - -output "out" { - value = module.mod.out -} -`, - - "./mod/main.tf": ` -variable "input" { - type = string -} - -output "out" { - value = var.input - - precondition { - condition = var.input != "" - error_message = "error" - } -} -`, - }) - - p := simpleMockProvider() - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - _, diags := ctx.Eval(m, states.NewState(), addrs.RootModuleInstance, &EvalOpts{ - SetVariables: testInputValuesUnset(m.Module.Variables), - }) - assertNoErrors(t, diags) -} diff --git a/internal/terraform/context_fixtures_test.go b/internal/terraform/context_fixtures_test.go deleted file mode 100644 index 2e9e9c27511d..000000000000 --- a/internal/terraform/context_fixtures_test.go +++ /dev/null @@ -1,85 +0,0 @@ -package terraform - -import ( - "testing" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/provisioners" - "github.com/zclconf/go-cty/cty" -) - -// contextTestFixture is a container for a set of objects that work together -// to create a base testing scenario. This is used to represent some common -// situations used as the basis for multiple tests. -type contextTestFixture struct { - Config *configs.Config - Providers map[addrs.Provider]providers.Factory - Provisioners map[string]provisioners.Factory -} - -// ContextOpts returns a ContextOps pre-populated with the elements of this -// fixture. Each call returns a distinct object, so callers can apply further -// _shallow_ modifications to the options as needed. -func (f *contextTestFixture) ContextOpts() *ContextOpts { - return &ContextOpts{ - Providers: f.Providers, - Provisioners: f.Provisioners, - } -} - -// contextFixtureApplyVars builds and returns a test fixture for testing -// input variables, primarily during the apply phase. The configuration is -// loaded from testdata/apply-vars, and the provider resolver is -// configured with a resource type schema for aws_instance that matches -// what's used in that configuration. -func contextFixtureApplyVars(t *testing.T) *contextTestFixture { - c := testModule(t, "apply-vars") - p := mockProviderWithResourceTypeSchema("aws_instance", &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Computed: true}, - "foo": {Type: cty.String, Optional: true}, - "bar": {Type: cty.String, Optional: true}, - "baz": {Type: cty.String, Optional: true}, - "num": {Type: cty.Number, Optional: true}, - "list": {Type: cty.List(cty.String), Optional: true}, - "map": {Type: cty.Map(cty.String), Optional: true}, - }, - }) - p.ApplyResourceChangeFn = testApplyFn - p.PlanResourceChangeFn = testDiffFn - return &contextTestFixture{ - Config: c, - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - } -} - -// contextFixtureApplyVarsEnv builds and returns a test fixture for testing -// input variables set from the environment. The configuration is -// loaded from testdata/apply-vars-env, and the provider resolver is -// configured with a resource type schema for aws_instance that matches -// what's used in that configuration. -func contextFixtureApplyVarsEnv(t *testing.T) *contextTestFixture { - c := testModule(t, "apply-vars-env") - p := mockProviderWithResourceTypeSchema("aws_instance", &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "string": {Type: cty.String, Optional: true}, - "list": {Type: cty.List(cty.String), Optional: true}, - "map": {Type: cty.Map(cty.String), Optional: true}, - "id": {Type: cty.String, Computed: true}, - "type": {Type: cty.String, Computed: true}, - }, - }) - p.ApplyResourceChangeFn = testApplyFn - p.PlanResourceChangeFn = testDiffFn - return &contextTestFixture{ - Config: c, - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - } -} diff --git a/internal/terraform/context_import.go b/internal/terraform/context_import.go deleted file mode 100644 index ac469e3cb85b..000000000000 --- a/internal/terraform/context_import.go +++ /dev/null @@ -1,92 +0,0 @@ -package terraform - -import ( - "log" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -// ImportOpts are used as the configuration for Import. -type ImportOpts struct { - // Targets are the targets to import - Targets []*ImportTarget - - // SetVariables are the variables set outside of the configuration, - // such as on the command line, in variables files, etc. - SetVariables InputValues -} - -// ImportTarget is a single resource to import. -type ImportTarget struct { - // Addr is the address for the resource instance that the new object should - // be imported into. - Addr addrs.AbsResourceInstance - - // ID is the ID of the resource to import. This is resource-specific. - ID string - - // ProviderAddr is the address of the provider that should handle the import. - ProviderAddr addrs.AbsProviderConfig -} - -// Import takes already-created external resources and brings them -// under Terraform management. Import requires the exact type, name, and ID -// of the resources to import. -// -// This operation is idempotent. If the requested resource is already -// imported, no changes are made to the state. -// -// Further, this operation also gracefully handles partial state. If during -// an import there is a failure, all previously imported resources remain -// imported. -func (c *Context) Import(config *configs.Config, prevRunState *states.State, opts *ImportOpts) (*states.State, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - - // Hold a lock since we can modify our own state here - defer c.acquireRun("import")() - - // Don't modify our caller's state - state := prevRunState.DeepCopy() - - log.Printf("[DEBUG] Building and walking import graph") - - variables := opts.SetVariables - - // Initialize our graph builder - builder := &PlanGraphBuilder{ - ImportTargets: opts.Targets, - Config: config, - State: state, - RootVariableValues: variables, - Plugins: c.plugins, - Operation: walkImport, - } - - // Build the graph - graph, graphDiags := builder.Build(addrs.RootModuleInstance) - diags = diags.Append(graphDiags) - if graphDiags.HasErrors() { - return state, diags - } - - // Walk it - walker, walkDiags := c.walk(graph, walkImport, &graphWalkOpts{ - Config: config, - InputState: state, - }) - diags = diags.Append(walkDiags) - if walkDiags.HasErrors() { - return state, diags - } - - // Data sources which could not be read during the import plan will be - // unknown. We need to strip those objects out so that the state can be - // serialized. - walker.State.RemovePlannedResourceInstanceObjects() - - newState := walker.State.Close() - return newState, diags -} diff --git a/internal/terraform/context_import_test.go b/internal/terraform/context_import_test.go deleted file mode 100644 index 920fe234384e..000000000000 --- a/internal/terraform/context_import_test.go +++ /dev/null @@ -1,1042 +0,0 @@ -package terraform - -import ( - "errors" - "strings" - "testing" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" - "github.com/zclconf/go-cty/cty" -) - -func TestContextImport_basic(t *testing.T) { - p := testProvider("aws") - m := testModule(t, "import-provider") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ - ImportedResources: []providers.ImportedResource{ - { - TypeName: "aws_instance", - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("foo"), - }), - }, - }, - } - - state, diags := ctx.Import(m, states.NewState(), &ImportOpts{ - Targets: []*ImportTarget{ - { - Addr: addrs.RootModuleInstance.ResourceInstance( - addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey, - ), - ID: "bar", - }, - }, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testImportStr) - if actual != expected { - t.Fatalf("wrong final state\ngot:\n%s\nwant:\n%s", actual, expected) - } -} - -// import 1 of count instances in the configuration -func TestContextImport_countIndex(t *testing.T) { - p := testProvider("aws") - m := testModuleInline(t, map[string]string{ - "main.tf": ` -provider "aws" { - foo = "bar" -} - -resource "aws_instance" "foo" { - count = 2 -} -`}) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ - ImportedResources: []providers.ImportedResource{ - { - TypeName: "aws_instance", - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("foo"), - }), - }, - }, - } - - state, diags := ctx.Import(m, states.NewState(), &ImportOpts{ - Targets: []*ImportTarget{ - { - Addr: addrs.RootModuleInstance.ResourceInstance( - addrs.ManagedResourceMode, "aws_instance", "foo", addrs.IntKey(0), - ), - ID: "bar", - }, - }, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testImportCountIndexStr) - if actual != expected { - t.Fatalf("bad: \n%s", actual) - } -} - -func TestContextImport_collision(t *testing.T) { - p := testProvider("aws") - m := testModule(t, "import-provider") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - state := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "foo", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - &states.ResourceInstanceObjectSrc{ - AttrsFlat: map[string]string{ - "id": "bar", - }, - Status: states.ObjectReady, - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("aws"), - Module: addrs.RootModule, - }, - ) - }) - - p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ - ImportedResources: []providers.ImportedResource{ - { - TypeName: "aws_instance", - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("foo"), - }), - }, - }, - } - - state, diags := ctx.Import(m, state, &ImportOpts{ - Targets: []*ImportTarget{ - { - Addr: addrs.RootModuleInstance.ResourceInstance( - addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey, - ), - ID: "bar", - }, - }, - }) - if !diags.HasErrors() { - t.Fatalf("succeeded; want an error indicating that the resource already exists in state") - } - - actual := strings.TrimSpace(state.String()) - expected := `aws_instance.foo: - ID = bar - provider = provider["registry.terraform.io/hashicorp/aws"]` - - if actual != expected { - t.Fatalf("bad: \n%s", actual) - } -} - -func TestContextImport_missingType(t *testing.T) { - p := testProvider("aws") - m := testModule(t, "import-provider") - - p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ - ImportedResources: []providers.ImportedResource{ - { - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("foo"), - }), - }, - }, - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - state, diags := ctx.Import(m, states.NewState(), &ImportOpts{ - Targets: []*ImportTarget{ - { - Addr: addrs.RootModuleInstance.ResourceInstance( - addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey, - ), - ID: "bar", - }, - }, - }) - if !diags.HasErrors() { - t.Fatal("should error") - } - - actual := strings.TrimSpace(state.String()) - expected := "" - if actual != expected { - t.Fatalf("bad: \n%s", actual) - } -} - -func TestContextImport_moduleProvider(t *testing.T) { - p := testProvider("aws") - - p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ - ImportedResources: []providers.ImportedResource{ - { - TypeName: "aws_instance", - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("foo"), - }), - }, - }, - } - - p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) { - foo := req.Config.GetAttr("foo").AsString() - if foo != "bar" { - resp.Diagnostics = resp.Diagnostics.Append(errors.New("not bar")) - } - - return - } - - m := testModule(t, "import-provider") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - state, diags := ctx.Import(m, states.NewState(), &ImportOpts{ - Targets: []*ImportTarget{ - { - Addr: addrs.RootModuleInstance.ResourceInstance( - addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey, - ), - ID: "bar", - }, - }, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - if !p.ConfigureProviderCalled { - t.Fatal("didn't configure provider") - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testImportStr) - if actual != expected { - t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) - } -} - -// Importing into a module requires a provider config in that module. -func TestContextImport_providerModule(t *testing.T) { - p := testProvider("aws") - m := testModule(t, "import-module") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ - ImportedResources: []providers.ImportedResource{ - { - TypeName: "aws_instance", - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("foo"), - }), - }, - }, - } - - p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) { - foo := req.Config.GetAttr("foo").AsString() - if foo != "bar" { - resp.Diagnostics = resp.Diagnostics.Append(errors.New("not bar")) - } - - return - } - - _, diags := ctx.Import(m, states.NewState(), &ImportOpts{ - Targets: []*ImportTarget{ - { - Addr: addrs.RootModuleInstance.Child("child", addrs.NoKey).ResourceInstance( - addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey, - ), - ID: "bar", - }, - }, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - if !p.ConfigureProviderCalled { - t.Fatal("didn't configure provider") - } -} - -// Test that import will interpolate provider configuration and use -// that configuration for import. -func TestContextImport_providerConfig(t *testing.T) { - testCases := map[string]struct { - module string - value string - }{ - "variables": { - module: "import-provider-vars", - value: "bar", - }, - "locals": { - module: "import-provider-locals", - value: "baz-bar", - }, - } - for name, test := range testCases { - t.Run(name, func(t *testing.T) { - p := testProvider("aws") - m := testModule(t, test.module) - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ - ImportedResources: []providers.ImportedResource{ - { - TypeName: "aws_instance", - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("foo"), - }), - }, - }, - } - - state, diags := ctx.Import(m, states.NewState(), &ImportOpts{ - Targets: []*ImportTarget{ - { - Addr: addrs.RootModuleInstance.ResourceInstance( - addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey, - ), - ID: "bar", - }, - }, - SetVariables: InputValues{ - "foo": &InputValue{ - Value: cty.StringVal("bar"), - SourceType: ValueFromCaller, - }, - }, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - if !p.ConfigureProviderCalled { - t.Fatal("didn't configure provider") - } - - if foo := p.ConfigureProviderRequest.Config.GetAttr("foo").AsString(); foo != test.value { - t.Fatalf("bad value %#v; want %#v", foo, test.value) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testImportStr) - if actual != expected { - t.Fatalf("bad: \n%s", actual) - } - }) - } -} - -// Test that provider configs can't reference resources. -func TestContextImport_providerConfigResources(t *testing.T) { - p := testProvider("aws") - pTest := testProvider("test") - m := testModule(t, "import-provider-resources") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - addrs.NewDefaultProvider("test"): testProviderFuncFixed(pTest), - }, - }) - - p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ - ImportedResources: []providers.ImportedResource{ - { - TypeName: "aws_instance", - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("foo"), - }), - }, - }, - } - - _, diags := ctx.Import(m, states.NewState(), &ImportOpts{ - Targets: []*ImportTarget{ - { - Addr: addrs.RootModuleInstance.ResourceInstance( - addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey, - ), - ID: "bar", - }, - }, - }) - if !diags.HasErrors() { - t.Fatal("should error") - } - if got, want := diags.Err().Error(), `The configuration for provider["registry.terraform.io/hashicorp/aws"] depends on values that cannot be determined until apply.`; !strings.Contains(got, want) { - t.Errorf("wrong error\n got: %s\nwant: %s", got, want) - } -} - -func TestContextImport_refresh(t *testing.T) { - p := testProvider("aws") - m := testModuleInline(t, map[string]string{ - "main.tf": ` -provider "aws" { - foo = "bar" -} - -resource "aws_instance" "foo" { -} - - -// we are only importing aws_instance.foo, so these resources will be unknown -resource "aws_instance" "bar" { -} -data "aws_data_source" "bar" { - foo = aws_instance.bar.id -} -`}) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ - ImportedResources: []providers.ImportedResource{ - { - TypeName: "aws_instance", - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("foo"), - }), - }, - }, - } - - p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{ - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("id"), - "foo": cty.UnknownVal(cty.String), - }), - } - - p.ReadResourceFn = nil - - p.ReadResourceResponse = &providers.ReadResourceResponse{ - NewState: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("foo"), - "foo": cty.StringVal("bar"), - }), - } - - state, diags := ctx.Import(m, states.NewState(), &ImportOpts{ - Targets: []*ImportTarget{ - { - Addr: addrs.RootModuleInstance.ResourceInstance( - addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey, - ), - ID: "bar", - }, - }, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - if d := state.ResourceInstance(mustResourceInstanceAddr("data.aws_data_source.bar")); d != nil { - t.Errorf("data.aws_data_source.bar has a status of ObjectPlanned and should not be in the state\ngot:%#v\n", d.Current) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testImportRefreshStr) - if actual != expected { - t.Fatalf("bad: \n%s", actual) - } -} - -func TestContextImport_refreshNil(t *testing.T) { - p := testProvider("aws") - m := testModule(t, "import-provider") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ - ImportedResources: []providers.ImportedResource{ - { - TypeName: "aws_instance", - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("foo"), - }), - }, - }, - } - - p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse { - return providers.ReadResourceResponse{ - NewState: cty.NullVal(cty.DynamicPseudoType), - } - } - - state, diags := ctx.Import(m, states.NewState(), &ImportOpts{ - Targets: []*ImportTarget{ - { - Addr: addrs.RootModuleInstance.ResourceInstance( - addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey, - ), - ID: "bar", - }, - }, - }) - if !diags.HasErrors() { - t.Fatal("should error") - } - - actual := strings.TrimSpace(state.String()) - expected := "" - if actual != expected { - t.Fatalf("bad: \n%s", actual) - } -} - -func TestContextImport_module(t *testing.T) { - p := testProvider("aws") - m := testModule(t, "import-module") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ - ImportedResources: []providers.ImportedResource{ - { - TypeName: "aws_instance", - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("foo"), - }), - }, - }, - } - - state, diags := ctx.Import(m, states.NewState(), &ImportOpts{ - Targets: []*ImportTarget{ - { - Addr: addrs.RootModuleInstance.Child("child", addrs.IntKey(0)).ResourceInstance( - addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey, - ), - ID: "bar", - }, - }, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testImportModuleStr) - if actual != expected { - t.Fatalf("bad: \n%s", actual) - } -} - -func TestContextImport_moduleDepth2(t *testing.T) { - p := testProvider("aws") - m := testModule(t, "import-module") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ - ImportedResources: []providers.ImportedResource{ - { - TypeName: "aws_instance", - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("foo"), - }), - }, - }, - } - - state, diags := ctx.Import(m, states.NewState(), &ImportOpts{ - Targets: []*ImportTarget{ - { - Addr: addrs.RootModuleInstance.Child("child", addrs.IntKey(0)).Child("nested", addrs.NoKey).ResourceInstance( - addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey, - ), - ID: "baz", - }, - }, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testImportModuleDepth2Str) - if actual != expected { - t.Fatalf("bad: \n%s", actual) - } -} - -func TestContextImport_moduleDiff(t *testing.T) { - p := testProvider("aws") - m := testModule(t, "import-module") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ - ImportedResources: []providers.ImportedResource{ - { - TypeName: "aws_instance", - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("foo"), - }), - }, - }, - } - - state, diags := ctx.Import(m, states.NewState(), &ImportOpts{ - Targets: []*ImportTarget{ - { - Addr: addrs.RootModuleInstance.Child("child", addrs.IntKey(0)).ResourceInstance( - addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey, - ), - ID: "baz", - }, - }, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testImportModuleStr) - if actual != expected { - t.Fatalf("\nexpected: %q\ngot: %q\n", expected, actual) - } -} - -func TestContextImport_multiState(t *testing.T) { - p := testProvider("aws") - m := testModule(t, "import-provider") - - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - Provider: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Computed: true}, - }, - }, - "aws_instance_thing": { - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Computed: true}, - }, - }, - }, - }) - - p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ - ImportedResources: []providers.ImportedResource{ - { - TypeName: "aws_instance", - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("foo"), - }), - }, - { - TypeName: "aws_instance_thing", - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("bar"), - }), - }, - }, - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - state, diags := ctx.Import(m, states.NewState(), &ImportOpts{ - Targets: []*ImportTarget{ - { - Addr: addrs.RootModuleInstance.ResourceInstance( - addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey, - ), - ID: "bar", - }, - }, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testImportMultiStr) - if actual != expected { - t.Fatalf("bad: \n%s", actual) - } -} - -func TestContextImport_multiStateSame(t *testing.T) { - p := testProvider("aws") - m := testModule(t, "import-provider") - - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - Provider: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Computed: true}, - }, - }, - "aws_instance_thing": { - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Computed: true}, - }, - }, - }, - }) - - p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ - ImportedResources: []providers.ImportedResource{ - { - TypeName: "aws_instance", - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("foo"), - }), - }, - { - TypeName: "aws_instance_thing", - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("bar"), - }), - }, - { - TypeName: "aws_instance_thing", - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("qux"), - }), - }, - }, - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - state, diags := ctx.Import(m, states.NewState(), &ImportOpts{ - Targets: []*ImportTarget{ - { - Addr: addrs.RootModuleInstance.ResourceInstance( - addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey, - ), - ID: "bar", - }, - }, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - actual := strings.TrimSpace(state.String()) - expected := strings.TrimSpace(testImportMultiSameStr) - if actual != expected { - t.Fatalf("bad: \n%s", actual) - } -} - -func TestContextImport_nestedModuleImport(t *testing.T) { - p := testProvider("aws") - m := testModuleInline(t, map[string]string{ - "main.tf": ` -locals { - xs = toset(["foo"]) -} - -module "a" { - for_each = local.xs - source = "./a" -} - -module "b" { - for_each = local.xs - source = "./b" - y = module.a[each.key].y -} - -resource "test_resource" "test" { -} -`, - "a/main.tf": ` -output "y" { - value = "bar" -} -`, - "b/main.tf": ` -variable "y" { - type = string -} - -resource "test_resource" "unused" { - value = var.y - // missing required, but should not error -} -`, - }) - - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - Provider: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - ResourceTypes: map[string]*configschema.Block{ - "test_resource": { - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Computed: true}, - "required": {Type: cty.String, Required: true}, - }, - }, - }, - }) - - p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ - ImportedResources: []providers.ImportedResource{ - { - TypeName: "test_resource", - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("test"), - "required": cty.StringVal("value"), - }), - }, - }, - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - state, diags := ctx.Import(m, states.NewState(), &ImportOpts{ - Targets: []*ImportTarget{ - { - Addr: addrs.RootModuleInstance.ResourceInstance( - addrs.ManagedResourceMode, "test_resource", "test", addrs.NoKey, - ), - ID: "test", - }, - }, - }) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - - ri := state.ResourceInstance(mustResourceInstanceAddr("test_resource.test")) - expected := `{"id":"test","required":"value"}` - if ri == nil || ri.Current == nil { - t.Fatal("no state is recorded for resource instance test_resource.test") - } - if string(ri.Current.AttrsJSON) != expected { - t.Fatalf("expected %q, got %q\n", expected, ri.Current.AttrsJSON) - } -} - -// New resources in the config during import won't exist for evaluation -// purposes (until import is upgraded to using a complete plan). This means -// that references to them are unknown, but in the case of single instances, we -// can at least know the type of unknown value. -func TestContextImport_newResourceUnknown(t *testing.T) { - p := testProvider("aws") - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "test_resource" "one" { -} - -resource "test_resource" "two" { - count = length(flatten([test_resource.one.id])) -} - -resource "test_resource" "test" { -} -`}) - - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test_resource": { - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Computed: true}, - }, - }, - }, - }) - - p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ - ImportedResources: []providers.ImportedResource{ - { - TypeName: "test_resource", - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("test"), - }), - }, - }, - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - state, diags := ctx.Import(m, states.NewState(), &ImportOpts{ - Targets: []*ImportTarget{ - { - Addr: addrs.RootModuleInstance.ResourceInstance( - addrs.ManagedResourceMode, "test_resource", "test", addrs.NoKey, - ), - ID: "test", - }, - }, - }) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - - ri := state.ResourceInstance(mustResourceInstanceAddr("test_resource.test")) - expected := `{"id":"test"}` - if ri == nil || ri.Current == nil { - t.Fatal("no state is recorded for resource instance test_resource.test") - } - if string(ri.Current.AttrsJSON) != expected { - t.Fatalf("expected %q, got %q\n", expected, ri.Current.AttrsJSON) - } -} - -const testImportStr = ` -aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] -` - -const testImportCountIndexStr = ` -aws_instance.foo.0: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] -` - -const testImportModuleStr = ` - -module.child[0]: - aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] -` - -const testImportModuleDepth2Str = ` - -module.child[0].nested: - aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] -` - -const testImportMultiStr = ` -aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] -aws_instance_thing.foo: - ID = bar - provider = provider["registry.terraform.io/hashicorp/aws"] -` - -const testImportMultiSameStr = ` -aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] -aws_instance_thing.foo: - ID = bar - provider = provider["registry.terraform.io/hashicorp/aws"] -aws_instance_thing.foo-1: - ID = qux - provider = provider["registry.terraform.io/hashicorp/aws"] -` - -const testImportRefreshStr = ` -aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = bar -` diff --git a/internal/terraform/context_input.go b/internal/terraform/context_input.go deleted file mode 100644 index 153546d2868b..000000000000 --- a/internal/terraform/context_input.go +++ /dev/null @@ -1,206 +0,0 @@ -package terraform - -import ( - "context" - "log" - "sort" - - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/zclconf/go-cty/cty" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -// Input asks for input to fill unset required arguments in provider -// configurations. -// -// Unlike the other better-behaved operation methods, this one actually -// modifies some internal state inside the receving context so that the -// captured values will be implicitly available to a subsequent call to Plan, -// or to some other operation entry point. Hopefully a future iteration of -// this will change design to make that data flow more explicit. -// -// Because Input saves the results inside the Context object, asking for -// input twice on the same Context is invalid and will lead to undefined -// behavior. -// -// Once you've called Input with a particular config, it's invalid to call -// any other Context method with a different config, because the aforementioned -// modified internal state won't match. Again, this is an architectural wart -// that we'll hopefully resolve in future. -func (c *Context) Input(config *configs.Config, mode InputMode) tfdiags.Diagnostics { - // This function used to be responsible for more than it is now, so its - // interface is more general than its current functionality requires. - // It now exists only to handle interactive prompts for provider - // configurations, with other prompts the responsibility of the CLI - // layer prior to calling in to this package. - // - // (Hopefully in future the remaining functionality here can move to the - // CLI layer too in order to avoid this odd situation where core code - // produces UI input prompts.) - - var diags tfdiags.Diagnostics - defer c.acquireRun("input")() - - schemas, moreDiags := c.Schemas(config, nil) - diags = diags.Append(moreDiags) - if moreDiags.HasErrors() { - return diags - } - - if c.uiInput == nil { - log.Printf("[TRACE] Context.Input: uiInput is nil, so skipping") - return diags - } - - ctx := context.Background() - - if mode&InputModeProvider != 0 { - log.Printf("[TRACE] Context.Input: Prompting for provider arguments") - - // We prompt for input only for provider configurations defined in - // the root module. Provider configurations in other modules are a - // legacy thing we no longer recommend, and even if they weren't we - // can't practically prompt for their inputs here because we've not - // yet done "expansion" and so we don't know whether the modules are - // using count or for_each. - - pcs := make(map[string]*configs.Provider) - pas := make(map[string]addrs.LocalProviderConfig) - for _, pc := range config.Module.ProviderConfigs { - addr := pc.Addr() - pcs[addr.String()] = pc - pas[addr.String()] = addr - log.Printf("[TRACE] Context.Input: Provider %s declared at %s", addr, pc.DeclRange) - } - // We also need to detect _implied_ provider configs from resources. - // These won't have *configs.Provider objects, but they will still - // exist in the map and we'll just treat them as empty below. - for _, rc := range config.Module.ManagedResources { - pa := rc.ProviderConfigAddr() - if pa.Alias != "" { - continue // alias configurations cannot be implied - } - if _, exists := pcs[pa.String()]; !exists { - pcs[pa.String()] = nil - pas[pa.String()] = pa - log.Printf("[TRACE] Context.Input: Provider %s implied by resource block at %s", pa, rc.DeclRange) - } - } - for _, rc := range config.Module.DataResources { - pa := rc.ProviderConfigAddr() - if pa.Alias != "" { - continue // alias configurations cannot be implied - } - if _, exists := pcs[pa.String()]; !exists { - pcs[pa.String()] = nil - pas[pa.String()] = pa - log.Printf("[TRACE] Context.Input: Provider %s implied by data block at %s", pa, rc.DeclRange) - } - } - - for pk, pa := range pas { - pc := pcs[pk] // will be nil if this is an implied config - - // Wrap the input into a namespace - input := &PrefixUIInput{ - IdPrefix: pk, - QueryPrefix: pk + ".", - UIInput: c.uiInput, - } - - providerFqn := config.Module.ProviderForLocalConfig(pa) - schema := schemas.ProviderConfig(providerFqn) - if schema == nil { - // Could either be an incorrect config or just an incomplete - // mock in tests. We'll let a later pass decide, and just - // ignore this for the purposes of gathering input. - log.Printf("[TRACE] Context.Input: No schema available for provider type %q", pa.LocalName) - continue - } - - // For our purposes here we just want to detect if attrbutes are - // set in config at all, so rather than doing a full decode - // (which would require us to prepare an evalcontext, etc) we'll - // use the low-level HCL API to process only the top-level - // structure. - var attrExprs hcl.Attributes // nil if there is no config - if pc != nil && pc.Config != nil { - lowLevelSchema := schemaForInputSniffing(hcldec.ImpliedSchema(schema.DecoderSpec())) - content, _, diags := pc.Config.PartialContent(lowLevelSchema) - if diags.HasErrors() { - log.Printf("[TRACE] Context.Input: %s has decode error, so ignoring: %s", pa, diags.Error()) - continue - } - attrExprs = content.Attributes - } - - keys := make([]string, 0, len(schema.Attributes)) - for key := range schema.Attributes { - keys = append(keys, key) - } - sort.Strings(keys) - - vals := map[string]cty.Value{} - for _, key := range keys { - attrS := schema.Attributes[key] - if attrS.Optional { - continue - } - if attrExprs != nil { - if _, exists := attrExprs[key]; exists { - continue - } - } - if !attrS.Type.Equals(cty.String) { - continue - } - - log.Printf("[TRACE] Context.Input: Prompting for %s argument %s", pa, key) - rawVal, err := input.Input(ctx, &InputOpts{ - Id: key, - Query: key, - Description: attrS.Description, - }) - if err != nil { - log.Printf("[TRACE] Context.Input: Failed to prompt for %s argument %s: %s", pa, key, err) - continue - } - - vals[key] = cty.StringVal(rawVal) - } - - absConfigAddr := addrs.AbsProviderConfig{ - Provider: providerFqn, - Alias: pa.Alias, - Module: config.Path, - } - c.providerInputConfig[absConfigAddr.String()] = vals - - log.Printf("[TRACE] Context.Input: Input for %s: %#v", pk, vals) - } - } - - return diags -} - -// schemaForInputSniffing returns a transformed version of a given schema -// that marks all attributes as optional, which the Context.Input method can -// use to detect whether a required argument is set without missing arguments -// themselves generating errors. -func schemaForInputSniffing(schema *hcl.BodySchema) *hcl.BodySchema { - ret := &hcl.BodySchema{ - Attributes: make([]hcl.AttributeSchema, len(schema.Attributes)), - Blocks: schema.Blocks, - } - - for i, attrS := range schema.Attributes { - ret.Attributes[i] = attrS - ret.Attributes[i].Required = false - } - - return ret -} diff --git a/internal/terraform/context_input_test.go b/internal/terraform/context_input_test.go deleted file mode 100644 index 5216efb5965f..000000000000 --- a/internal/terraform/context_input_test.go +++ /dev/null @@ -1,469 +0,0 @@ -package terraform - -import ( - "reflect" - "strings" - "sync" - "testing" - - "github.com/zclconf/go-cty/cty" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" -) - -func TestContext2Input_provider(t *testing.T) { - m := testModule(t, "input-provider") - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - Provider: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": { - Type: cty.String, - Required: true, - Description: "something something", - }, - }, - }, - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - }, - }, - }, - }) - - inp := &MockUIInput{ - InputReturnMap: map[string]string{ - "provider.aws.foo": "bar", - }, - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - UIInput: inp, - }) - - var actual interface{} - p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) { - actual = req.Config.GetAttr("foo").AsString() - return - } - - if diags := ctx.Input(m, InputModeStd); diags.HasErrors() { - t.Fatalf("input errors: %s", diags.Err()) - } - - if !inp.InputCalled { - t.Fatal("no input prompt; want prompt for argument \"foo\"") - } - if got, want := inp.InputOpts.Description, "something something"; got != want { - t.Errorf("wrong description\ngot: %q\nwant: %q", got, want) - } - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - if _, diags := ctx.Apply(plan, m); diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } - - if !reflect.DeepEqual(actual, "bar") { - t.Fatalf("wrong result\ngot: %#v\nwant: %#v", actual, "bar") - } -} - -func TestContext2Input_providerMulti(t *testing.T) { - m := testModule(t, "input-provider-multi") - - getProviderSchemaResponse := getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - Provider: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": { - Type: cty.String, - Required: true, - Description: "something something", - }, - }, - }, - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - }, - }, - }, - }) - - // In order to update the provider to check only the configure calls during - // apply, we will need to inject a new factory function after plan. We must - // use a closure around the factory, because in order for the inputs to - // work during apply we need to maintain the same context value, preventing - // us from assigning a new Providers map. - providerFactory := func() (providers.Interface, error) { - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponse - return p, nil - } - - inp := &MockUIInput{ - InputReturnMap: map[string]string{ - "provider.aws.foo": "bar", - "provider.aws.east.foo": "bar", - }, - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): func() (providers.Interface, error) { - return providerFactory() - }, - }, - UIInput: inp, - }) - - var actual []interface{} - var lock sync.Mutex - - if diags := ctx.Input(m, InputModeStd); diags.HasErrors() { - t.Fatalf("input errors: %s", diags.Err()) - } - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - providerFactory = func() (providers.Interface, error) { - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponse - p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) { - lock.Lock() - defer lock.Unlock() - actual = append(actual, req.Config.GetAttr("foo").AsString()) - return - } - return p, nil - } - - if _, diags := ctx.Apply(plan, m); diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } - - expected := []interface{}{"bar", "bar"} - if !reflect.DeepEqual(actual, expected) { - t.Fatalf("wrong result\ngot: %#v\nwant: %#v", actual, expected) - } -} - -func TestContext2Input_providerOnce(t *testing.T) { - m := testModule(t, "input-provider-once") - p := testProvider("aws") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - if diags := ctx.Input(m, InputModeStd); diags.HasErrors() { - t.Fatalf("input errors: %s", diags.Err()) - } -} - -func TestContext2Input_providerId(t *testing.T) { - input := new(MockUIInput) - - m := testModule(t, "input-provider") - - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - Provider: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": { - Type: cty.String, - Required: true, - Description: "something something", - }, - }, - }, - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - }, - }, - }, - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - UIInput: input, - }) - - var actual interface{} - p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) { - actual = req.Config.GetAttr("foo").AsString() - return - } - - input.InputReturnMap = map[string]string{ - "provider.aws.foo": "bar", - } - - if diags := ctx.Input(m, InputModeStd); diags.HasErrors() { - t.Fatalf("input errors: %s", diags.Err()) - } - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - if _, diags := ctx.Apply(plan, m); diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } - - if !reflect.DeepEqual(actual, "bar") { - t.Fatalf("wrong result\ngot: %#v\nwant: %#v", actual, "bar") - } -} - -func TestContext2Input_providerOnly(t *testing.T) { - input := new(MockUIInput) - - m := testModule(t, "input-provider-vars") - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - Provider: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": { - Type: cty.String, - Required: true, - }, - }, - }, - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Required: true}, - "id": {Type: cty.String, Computed: true}, - "type": {Type: cty.String, Computed: true}, - }, - }, - }, - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - UIInput: input, - }) - - input.InputReturnMap = map[string]string{ - "provider.aws.foo": "bar", - } - - var actual interface{} - p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) { - actual = req.Config.GetAttr("foo").AsString() - return - } - - if err := ctx.Input(m, InputModeProvider); err != nil { - t.Fatalf("err: %s", err) - } - - // NOTE: This is a stale test case from an older version of Terraform - // where Input was responsible for prompting for both input variables _and_ - // provider configuration arguments, where it was trying to test the case - // where we were turning off the mode of prompting for input variables. - // That's now always disabled, and so this is essentially the same as the - // normal Input test, but we're preserving it until we have time to review - // and make sure this isn't inadvertently providing unique test coverage - // other than what it set out to test. - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "foo": &InputValue{ - Value: cty.StringVal("us-west-2"), - SourceType: ValueFromCaller, - }, - }, - }) - assertNoErrors(t, diags) - - state, err := ctx.Apply(plan, m) - if err != nil { - t.Fatalf("err: %s", err) - } - - if !reflect.DeepEqual(actual, "bar") { - t.Fatalf("wrong result\ngot: %#v\nwant: %#v", actual, "bar") - } - - actualStr := strings.TrimSpace(state.String()) - expectedStr := strings.TrimSpace(testTerraformInputProviderOnlyStr) - if actualStr != expectedStr { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actualStr, expectedStr) - } -} - -func TestContext2Input_providerVars(t *testing.T) { - input := new(MockUIInput) - m := testModule(t, "input-provider-with-vars") - p := testProvider("aws") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - UIInput: input, - }) - - input.InputReturnMap = map[string]string{ - "var.foo": "bar", - } - - var actual interface{} - p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) { - actual = req.Config.GetAttr("foo").AsString() - return - } - if diags := ctx.Input(m, InputModeStd); diags.HasErrors() { - t.Fatalf("input errors: %s", diags.Err()) - } - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "foo": &InputValue{ - Value: cty.StringVal("bar"), - SourceType: ValueFromCaller, - }, - }, - }) - assertNoErrors(t, diags) - - if _, diags := ctx.Apply(plan, m); diags.HasErrors() { - t.Fatalf("apply errors: %s", diags.Err()) - } - - if !reflect.DeepEqual(actual, "bar") { - t.Fatalf("bad: %#v", actual) - } -} - -func TestContext2Input_providerVarsModuleInherit(t *testing.T) { - input := new(MockUIInput) - m := testModule(t, "input-provider-with-vars-and-module") - p := testProvider("aws") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - UIInput: input, - }) - - if diags := ctx.Input(m, InputModeStd); diags.HasErrors() { - t.Fatalf("input errors: %s", diags.Err()) - } -} - -// adding a list interpolation in fails to interpolate the count variable -func TestContext2Input_submoduleTriggersInvalidCount(t *testing.T) { - input := new(MockUIInput) - m := testModule(t, "input-submodule-count") - p := testProvider("aws") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - UIInput: input, - }) - - if diags := ctx.Input(m, InputModeStd); diags.HasErrors() { - t.Fatalf("input errors: %s", diags.Err()) - } -} - -// In this case, a module variable can't be resolved from a data source until -// it's refreshed, but it can't be refreshed during Input. -func TestContext2Input_dataSourceRequiresRefresh(t *testing.T) { - input := new(MockUIInput) - p := testProvider("null") - m := testModule(t, "input-module-data-vars") - - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - DataSources: map[string]*configschema.Block{ - "null_data_source": { - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.List(cty.String), Optional: true}, - }, - }, - }, - }) - p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse { - return providers.ReadDataSourceResponse{ - State: req.Config, - } - } - - state := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.DataResourceMode, - Type: "null_data_source", - Name: "bar", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - &states.ResourceInstanceObjectSrc{ - AttrsFlat: map[string]string{ - "id": "-", - "foo.#": "1", - "foo.0": "a", - // foo.1 exists in the data source, but needs to be refreshed. - }, - Status: states.ObjectReady, - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("null"), - Module: addrs.RootModule, - }, - ) - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("null"): testProviderFuncFixed(p), - }, - UIInput: input, - }) - - if diags := ctx.Input(m, InputModeStd); diags.HasErrors() { - t.Fatalf("input errors: %s", diags.Err()) - } - - // ensure that plan works after Refresh. This is a legacy test that - // doesn't really make sense anymore, because Refresh is really just - // a wrapper around plan anyway, but we're keeping it until we get a - // chance to review and check whether it's giving us any additional - // test coverage aside from what it's specifically intending to test. - if _, diags := ctx.Refresh(m, state, DefaultPlanOpts); diags.HasErrors() { - t.Fatalf("refresh errors: %s", diags.Err()) - } - if _, diags := ctx.Plan(m, state, DefaultPlanOpts); diags.HasErrors() { - t.Fatalf("plan errors: %s", diags.Err()) - } -} diff --git a/internal/terraform/context_plan.go b/internal/terraform/context_plan.go deleted file mode 100644 index 416232a48031..000000000000 --- a/internal/terraform/context_plan.go +++ /dev/null @@ -1,867 +0,0 @@ -package terraform - -import ( - "bytes" - "fmt" - "log" - "sort" - "strings" - - "github.com/zclconf/go-cty/cty" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/instances" - "github.com/hashicorp/terraform/internal/lang/globalref" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/refactoring" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -// PlanOpts are the various options that affect the details of how Terraform -// will build a plan. -type PlanOpts struct { - // Mode defines what variety of plan the caller wishes to create. - // Refer to the documentation of the plans.Mode type and its values - // for more information. - Mode plans.Mode - - // SkipRefresh specifies to trust that the current values for managed - // resource instances in the prior state are accurate and to therefore - // disable the usual step of fetching updated values for each resource - // instance using its corresponding provider. - SkipRefresh bool - - // PreDestroyRefresh indicated that this is being passed to a plan used to - // refresh the state immediately before a destroy plan. - // FIXME: This is a temporary fix to allow the pre-destroy refresh to - // succeed. The refreshing operation during destroy must be a special case, - // which can allow for missing instances in the state, and avoid blocking - // on failing condition tests. The destroy plan itself should be - // responsible for this special case of refreshing, and the separate - // pre-destroy plan removed entirely. - PreDestroyRefresh bool - - // SetVariables are the raw values for root module variables as provided - // by the user who is requesting the run, prior to any normalization or - // substitution of defaults. See the documentation for the InputValue - // type for more information on how to correctly populate this. - SetVariables InputValues - - // If Targets has a non-zero length then it activates targeted planning - // mode, where Terraform will take actions only for resource instances - // mentioned in this set and any other objects those resource instances - // depend on. - // - // Targeted planning mode is intended for exceptional use only, - // and so populating this field will cause Terraform to generate extra - // warnings as part of the planning result. - Targets []addrs.Targetable - - // ForceReplace is a set of resource instance addresses whose corresponding - // objects should be forced planned for replacement if the provider's - // plan would otherwise have been to either update the object in-place or - // to take no action on it at all. - // - // A typical use of this argument is to ask Terraform to replace an object - // which the user has determined is somehow degraded (via information from - // outside of Terraform), thereby hopefully replacing it with a - // fully-functional new object. - ForceReplace []addrs.AbsResourceInstance -} - -// Plan generates an execution plan by comparing the given configuration -// with the given previous run state. -// -// The given planning options allow control of various other details of the -// planning process that are not represented directly in the configuration. -// You can use terraform.DefaultPlanOpts to generate a normal plan with no -// special options. -// -// If the returned diagnostics contains no errors then the returned plan is -// applyable, although Terraform cannot guarantee that applying it will fully -// succeed. If the returned diagnostics contains errors but this method -// still returns a non-nil Plan then the plan describes the subset of actions -// planned so far, which is not safe to apply but could potentially be used -// by the UI layer to give extra context to support understanding of the -// returned error messages. -func (c *Context) Plan(config *configs.Config, prevRunState *states.State, opts *PlanOpts) (*plans.Plan, tfdiags.Diagnostics) { - defer c.acquireRun("plan")() - var diags tfdiags.Diagnostics - - // Save the downstream functions from needing to deal with these broken situations. - // No real callers should rely on these, but we have a bunch of old and - // sloppy tests that don't always populate arguments properly. - if config == nil { - config = configs.NewEmptyConfig() - } - if prevRunState == nil { - prevRunState = states.NewState() - } - if opts == nil { - opts = &PlanOpts{ - Mode: plans.NormalMode, - } - } - - moreDiags := c.checkConfigDependencies(config) - diags = diags.Append(moreDiags) - // If required dependencies are not available then we'll bail early since - // otherwise we're likely to just see a bunch of other errors related to - // incompatibilities, which could be overwhelming for the user. - if diags.HasErrors() { - return nil, diags - } - - switch opts.Mode { - case plans.NormalMode, plans.DestroyMode: - // OK - case plans.RefreshOnlyMode: - if opts.SkipRefresh { - // The CLI layer (and other similar callers) should prevent this - // combination of options. - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Incompatible plan options", - "Cannot skip refreshing in refresh-only mode. This is a bug in Terraform.", - )) - return nil, diags - } - default: - // The CLI layer (and other similar callers) should not try to - // create a context for a mode that Terraform Core doesn't support. - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Unsupported plan mode", - fmt.Sprintf("Terraform Core doesn't know how to handle plan mode %s. This is a bug in Terraform.", opts.Mode), - )) - return nil, diags - } - if len(opts.ForceReplace) > 0 && opts.Mode != plans.NormalMode { - // The other modes don't generate no-op or update actions that we might - // upgrade to be "replace", so doesn't make sense to combine those. - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Unsupported plan mode", - "Forcing resource instance replacement (with -replace=...) is allowed only in normal planning mode.", - )) - return nil, diags - } - - // By the time we get here, we should have values defined for all of - // the root module variables, even if some of them are "unknown". It's the - // caller's responsibility to have already handled the decoding of these - // from the various ways the CLI allows them to be set and to produce - // user-friendly error messages if they are not all present, and so - // the error message from checkInputVariables should never be seen and - // includes language asking the user to report a bug. - varDiags := checkInputVariables(config.Module.Variables, opts.SetVariables) - diags = diags.Append(varDiags) - - if len(opts.Targets) > 0 { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Warning, - "Resource targeting is in effect", - `You are creating a plan with the -target option, which means that the result of this plan may not represent all of the changes requested by the current configuration. - -The -target option is not for routine use, and is provided only for exceptional situations such as recovering from errors or mistakes, or when Terraform specifically suggests to use it as part of an error message.`, - )) - } - - var plan *plans.Plan - var planDiags tfdiags.Diagnostics - switch opts.Mode { - case plans.NormalMode: - plan, planDiags = c.plan(config, prevRunState, opts) - case plans.DestroyMode: - plan, planDiags = c.destroyPlan(config, prevRunState, opts) - case plans.RefreshOnlyMode: - plan, planDiags = c.refreshOnlyPlan(config, prevRunState, opts) - default: - panic(fmt.Sprintf("unsupported plan mode %s", opts.Mode)) - } - diags = diags.Append(planDiags) - // NOTE: We're intentionally not returning early when diags.HasErrors - // here because we'll still populate other metadata below on a best-effort - // basis to try to give the UI some extra context to return alongside the - // error messages. - - // convert the variables into the format expected for the plan - varVals := make(map[string]plans.DynamicValue, len(opts.SetVariables)) - for k, iv := range opts.SetVariables { - if iv.Value == cty.NilVal { - continue // We only record values that the caller actually set - } - - // We use cty.DynamicPseudoType here so that we'll save both the - // value _and_ its dynamic type in the plan, so we can recover - // exactly the same value later. - dv, err := plans.NewDynamicValue(iv.Value, cty.DynamicPseudoType) - if err != nil { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Failed to prepare variable value for plan", - fmt.Sprintf("The value for variable %q could not be serialized to store in the plan: %s.", k, err), - )) - continue - } - varVals[k] = dv - } - - // insert the run-specific data from the context into the plan; variables, - // targets and provider SHAs. - if plan != nil { - plan.VariableValues = varVals - plan.TargetAddrs = opts.Targets - } else if !diags.HasErrors() { - panic("nil plan but no errors") - } - - if plan != nil { - relevantAttrs, rDiags := c.relevantResourceAttrsForPlan(config, plan) - diags = diags.Append(rDiags) - plan.RelevantAttributes = relevantAttrs - } - - if diags.HasErrors() { - // We can't proceed further with an invalid plan, because an invalid - // plan isn't applyable by definition. - if plan != nil { - // We'll explicitly mark our plan as errored so that it can't - // be accidentally applied even though it's incomplete. - plan.Errored = true - } - return plan, diags - } - - diags = diags.Append(c.checkApplyGraph(plan, config)) - - return plan, diags -} - -// checkApplyGraph builds the apply graph out of the current plan to -// check for any errors that may arise once the planned changes are added to -// the graph. This allows terraform to report errors (mostly cycles) during -// plan that would otherwise only crop up during apply -func (c *Context) checkApplyGraph(plan *plans.Plan, config *configs.Config) tfdiags.Diagnostics { - if plan.Changes.Empty() { - log.Println("[DEBUG] no planned changes, skipping apply graph check") - return nil - } - log.Println("[DEBUG] building apply graph to check for errors") - _, _, diags := c.applyGraph(plan, config, true) - return diags -} - -var DefaultPlanOpts = &PlanOpts{ - Mode: plans.NormalMode, -} - -// SimplePlanOpts is a constructor to help with creating "simple" values of -// PlanOpts which only specify a mode and input variables. -// -// This helper function is primarily intended for use in straightforward -// tests that don't need any of the more "esoteric" planning options. For -// handling real user requests to run Terraform, it'd probably be better -// to construct a *PlanOpts value directly and provide a way for the user -// to set values for all of its fields. -// -// The "mode" and "setVariables" arguments become the values of the "Mode" -// and "SetVariables" fields in the result. Refer to the PlanOpts type -// documentation to learn about the meanings of those fields. -func SimplePlanOpts(mode plans.Mode, setVariables InputValues) *PlanOpts { - return &PlanOpts{ - Mode: mode, - SetVariables: setVariables, - } -} - -func (c *Context) plan(config *configs.Config, prevRunState *states.State, opts *PlanOpts) (*plans.Plan, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - - if opts.Mode != plans.NormalMode { - panic(fmt.Sprintf("called Context.plan with %s", opts.Mode)) - } - - plan, walkDiags := c.planWalk(config, prevRunState, opts) - diags = diags.Append(walkDiags) - - return plan, diags -} - -func (c *Context) refreshOnlyPlan(config *configs.Config, prevRunState *states.State, opts *PlanOpts) (*plans.Plan, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - - if opts.Mode != plans.RefreshOnlyMode { - panic(fmt.Sprintf("called Context.refreshOnlyPlan with %s", opts.Mode)) - } - - plan, walkDiags := c.planWalk(config, prevRunState, opts) - diags = diags.Append(walkDiags) - if diags.HasErrors() { - // Non-nil plan along with errors indicates a non-applyable partial - // plan that's only suitable to be shown to the user as extra context - // to help understand the errors. - return plan, diags - } - - // If the graph builder and graph nodes correctly obeyed our directive - // to refresh only, the set of resource changes should always be empty. - // We'll safety-check that here so we can return a clear message about it, - // rather than probably just generating confusing output at the UI layer. - if len(plan.Changes.Resources) != 0 { - // Some extra context in the logs in case the user reports this message - // as a bug, as a starting point for debugging. - for _, rc := range plan.Changes.Resources { - if depKey := rc.DeposedKey; depKey == states.NotDeposed { - log.Printf("[DEBUG] Refresh-only plan includes %s change for %s", rc.Action, rc.Addr) - } else { - log.Printf("[DEBUG] Refresh-only plan includes %s change for %s deposed object %s", rc.Action, rc.Addr, depKey) - } - } - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Invalid refresh-only plan", - "Terraform generated planned resource changes in a refresh-only plan. This is a bug in Terraform.", - )) - } - - // We don't populate RelevantResources for a refresh-only plan, because - // they never have any planned actions and so no resource can ever be - // "relevant" per the intended meaning of that field. - - return plan, diags -} - -func (c *Context) destroyPlan(config *configs.Config, prevRunState *states.State, opts *PlanOpts) (*plans.Plan, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - - if opts.Mode != plans.DestroyMode { - panic(fmt.Sprintf("called Context.destroyPlan with %s", opts.Mode)) - } - - priorState := prevRunState - - // A destroy plan starts by running Refresh to read any pending data - // sources, and remove missing managed resources. This is required because - // a "destroy plan" is only creating delete changes, and is essentially a - // local operation. - // - // NOTE: if skipRefresh _is_ set then we'll rely on the destroy-plan walk - // below to upgrade the prevRunState and priorState both to the latest - // resource type schemas, so NodePlanDestroyableResourceInstance.Execute - // must coordinate with this by taking that action only when c.skipRefresh - // _is_ set. This coupling between the two is unfortunate but necessary - // to work within our current structure. - if !opts.SkipRefresh && !prevRunState.Empty() { - log.Printf("[TRACE] Context.destroyPlan: calling Context.plan to get the effect of refreshing the prior state") - refreshOpts := *opts - refreshOpts.Mode = plans.NormalMode - refreshOpts.PreDestroyRefresh = true - - // FIXME: A normal plan is required here to refresh the state, because - // the state and configuration may not match during a destroy, and a - // normal refresh plan can fail with evaluation errors. In the future - // the destroy plan should take care of refreshing instances itself, - // where the special cases of evaluation and skipping condition checks - // can be done. - refreshPlan, refreshDiags := c.plan(config, prevRunState, &refreshOpts) - if refreshDiags.HasErrors() { - // NOTE: Normally we'd append diagnostics regardless of whether - // there are errors, just in case there are warnings we'd want to - // preserve, but we're intentionally _not_ doing that here because - // if the first plan succeeded then we'll be running another plan - // in DestroyMode below, and we don't want to double-up any - // warnings that both plan walks would generate. - // (This does mean we won't show any warnings that would've been - // unique to only this walk, but we're assuming here that if the - // warnings aren't also applicable to a destroy plan then we'd - // rather not show them here, because this non-destroy plan for - // refreshing is largely an implementation detail.) - diags = diags.Append(refreshDiags) - return nil, diags - } - - // We'll use the refreshed state -- which is the "prior state" from - // the perspective of this "destroy plan" -- as the starting state - // for our destroy-plan walk, so it can take into account if we - // detected during refreshing that anything was already deleted outside - // of Terraform. - priorState = refreshPlan.PriorState.DeepCopy() - - // The refresh plan may have upgraded state for some resources, make - // sure we store the new version. - prevRunState = refreshPlan.PrevRunState.DeepCopy() - log.Printf("[TRACE] Context.destroyPlan: now _really_ creating a destroy plan") - } - - destroyPlan, walkDiags := c.planWalk(config, priorState, opts) - diags = diags.Append(walkDiags) - if walkDiags.HasErrors() { - // Non-nil plan along with errors indicates a non-applyable partial - // plan that's only suitable to be shown to the user as extra context - // to help understand the errors. - return destroyPlan, diags - } - - if !opts.SkipRefresh { - // If we didn't skip refreshing then we want the previous run state to - // be the one we originally fed into the c.refreshOnlyPlan call above, - // not the refreshed version we used for the destroy planWalk. - destroyPlan.PrevRunState = prevRunState - } - - relevantAttrs, rDiags := c.relevantResourceAttrsForPlan(config, destroyPlan) - diags = diags.Append(rDiags) - - destroyPlan.RelevantAttributes = relevantAttrs - return destroyPlan, diags -} - -func (c *Context) prePlanFindAndApplyMoves(config *configs.Config, prevRunState *states.State, targets []addrs.Targetable) ([]refactoring.MoveStatement, refactoring.MoveResults) { - explicitMoveStmts := refactoring.FindMoveStatements(config) - implicitMoveStmts := refactoring.ImpliedMoveStatements(config, prevRunState, explicitMoveStmts) - var moveStmts []refactoring.MoveStatement - if stmtsLen := len(explicitMoveStmts) + len(implicitMoveStmts); stmtsLen > 0 { - moveStmts = make([]refactoring.MoveStatement, 0, stmtsLen) - moveStmts = append(moveStmts, explicitMoveStmts...) - moveStmts = append(moveStmts, implicitMoveStmts...) - } - moveResults := refactoring.ApplyMoves(moveStmts, prevRunState) - return moveStmts, moveResults -} - -func (c *Context) prePlanVerifyTargetedMoves(moveResults refactoring.MoveResults, targets []addrs.Targetable) tfdiags.Diagnostics { - if len(targets) < 1 { - return nil // the following only matters when targeting - } - - var diags tfdiags.Diagnostics - - var excluded []addrs.AbsResourceInstance - for _, result := range moveResults.Changes.Values() { - fromMatchesTarget := false - toMatchesTarget := false - for _, targetAddr := range targets { - if targetAddr.TargetContains(result.From) { - fromMatchesTarget = true - } - if targetAddr.TargetContains(result.To) { - toMatchesTarget = true - } - } - if !fromMatchesTarget { - excluded = append(excluded, result.From) - } - if !toMatchesTarget { - excluded = append(excluded, result.To) - } - } - if len(excluded) > 0 { - sort.Slice(excluded, func(i, j int) bool { - return excluded[i].Less(excluded[j]) - }) - - var listBuf strings.Builder - var prevResourceAddr addrs.AbsResource - for _, instAddr := range excluded { - // Targeting generally ends up selecting whole resources rather - // than individual instances, because we don't factor in - // individual instances until DynamicExpand, so we're going to - // always show whole resource addresses here, excluding any - // instance keys. (This also neatly avoids dealing with the - // different quoting styles required for string instance keys - // on different shells, which is handy.) - // - // To avoid showing duplicates when we have multiple instances - // of the same resource, we'll remember the most recent - // resource we rendered in prevResource, which is sufficient - // because we sorted the list of instance addresses above, and - // our sort order always groups together instances of the same - // resource. - resourceAddr := instAddr.ContainingResource() - if resourceAddr.Equal(prevResourceAddr) { - continue - } - fmt.Fprintf(&listBuf, "\n -target=%q", resourceAddr.String()) - prevResourceAddr = resourceAddr - } - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Moved resource instances excluded by targeting", - fmt.Sprintf( - "Resource instances in your current state have moved to new addresses in the latest configuration. Terraform must include those resource instances while planning in order to ensure a correct result, but your -target=... options to not fully cover all of those resource instances.\n\nTo create a valid plan, either remove your -target=... options altogether or add the following additional target options:%s\n\nNote that adding these options may include further additional resource instances in your plan, in order to respect object dependencies.", - listBuf.String(), - ), - )) - } - - return diags -} - -func (c *Context) postPlanValidateMoves(config *configs.Config, stmts []refactoring.MoveStatement, allInsts instances.Set) tfdiags.Diagnostics { - return refactoring.ValidateMoves(stmts, config, allInsts) -} - -func (c *Context) planWalk(config *configs.Config, prevRunState *states.State, opts *PlanOpts) (*plans.Plan, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - log.Printf("[DEBUG] Building and walking plan graph for %s", opts.Mode) - - prevRunState = prevRunState.DeepCopy() // don't modify the caller's object when we process the moves - moveStmts, moveResults := c.prePlanFindAndApplyMoves(config, prevRunState, opts.Targets) - - // If resource targeting is in effect then it might conflict with the - // move result. - diags = diags.Append(c.prePlanVerifyTargetedMoves(moveResults, opts.Targets)) - if diags.HasErrors() { - // We'll return early here, because if we have any moved resource - // instances excluded by targeting then planning is likely to encounter - // strange problems that may lead to confusing error messages. - return nil, diags - } - - graph, walkOp, moreDiags := c.planGraph(config, prevRunState, opts) - diags = diags.Append(moreDiags) - if diags.HasErrors() { - return nil, diags - } - - // If we get here then we should definitely have a non-nil "graph", which - // we can now walk. - changes := plans.NewChanges() - walker, walkDiags := c.walk(graph, walkOp, &graphWalkOpts{ - Config: config, - InputState: prevRunState, - Changes: changes, - MoveResults: moveResults, - }) - diags = diags.Append(walker.NonFatalDiagnostics) - diags = diags.Append(walkDiags) - moveValidateDiags := c.postPlanValidateMoves(config, moveStmts, walker.InstanceExpander.AllInstances()) - if moveValidateDiags.HasErrors() { - // If any of the move statements are invalid then those errors take - // precedence over any other errors because an incomplete move graph - // is quite likely to be the _cause_ of various errors. This oddity - // comes from the fact that we need to apply the moves before we - // actually validate them, because validation depends on the result - // of first trying to plan. - return nil, moveValidateDiags - } - diags = diags.Append(moveValidateDiags) // might just contain warnings - - if moveResults.Blocked.Len() > 0 && !diags.HasErrors() { - // If we had blocked moves and we're not going to be returning errors - // then we'll report the blockers as a warning. We do this only in the - // absense of errors because invalid move statements might well be - // the root cause of the blockers, and so better to give an actionable - // error message than a less-actionable warning. - diags = diags.Append(blockedMovesWarningDiag(moveResults)) - } - - // If we reach this point with error diagnostics then "changes" is a - // representation of the subset of changes we were able to plan before - // we encountered errors, which we'll return as part of a non-nil plan - // so that e.g. the UI can show what was planned so far in case that extra - // context helps the user to understand the error messages we're returning. - prevRunState = walker.PrevRunState.Close() - - // The refreshed state may have data resource objects which were deferred - // to apply and cannot be serialized. - walker.RefreshState.RemovePlannedResourceInstanceObjects() - priorState := walker.RefreshState.Close() - - driftedResources, driftDiags := c.driftedResources(config, prevRunState, priorState, moveResults) - diags = diags.Append(driftDiags) - - plan := &plans.Plan{ - UIMode: opts.Mode, - Changes: changes, - DriftedResources: driftedResources, - PrevRunState: prevRunState, - PriorState: priorState, - Checks: states.NewCheckResults(walker.Checks), - - // Other fields get populated by Context.Plan after we return - } - return plan, diags -} - -func (c *Context) planGraph(config *configs.Config, prevRunState *states.State, opts *PlanOpts) (*Graph, walkOperation, tfdiags.Diagnostics) { - switch mode := opts.Mode; mode { - case plans.NormalMode: - graph, diags := (&PlanGraphBuilder{ - Config: config, - State: prevRunState, - RootVariableValues: opts.SetVariables, - Plugins: c.plugins, - Targets: opts.Targets, - ForceReplace: opts.ForceReplace, - skipRefresh: opts.SkipRefresh, - preDestroyRefresh: opts.PreDestroyRefresh, - Operation: walkPlan, - }).Build(addrs.RootModuleInstance) - return graph, walkPlan, diags - case plans.RefreshOnlyMode: - graph, diags := (&PlanGraphBuilder{ - Config: config, - State: prevRunState, - RootVariableValues: opts.SetVariables, - Plugins: c.plugins, - Targets: opts.Targets, - skipRefresh: opts.SkipRefresh, - skipPlanChanges: true, // this activates "refresh only" mode. - Operation: walkPlan, - }).Build(addrs.RootModuleInstance) - return graph, walkPlan, diags - case plans.DestroyMode: - graph, diags := (&PlanGraphBuilder{ - Config: config, - State: prevRunState, - RootVariableValues: opts.SetVariables, - Plugins: c.plugins, - Targets: opts.Targets, - skipRefresh: opts.SkipRefresh, - Operation: walkPlanDestroy, - }).Build(addrs.RootModuleInstance) - return graph, walkPlanDestroy, diags - default: - // The above should cover all plans.Mode values - panic(fmt.Sprintf("unsupported plan mode %s", mode)) - } -} - -// driftedResources is a best-effort attempt to compare the current and prior -// state. If we cannot decode the prior state for some reason, this should only -// return warnings to help the user correlate any missing resources in the -// report. This is known to happen when targeting a subset of resources, -// because the excluded instances will have been removed from the plan and -// not upgraded. -func (c *Context) driftedResources(config *configs.Config, oldState, newState *states.State, moves refactoring.MoveResults) ([]*plans.ResourceInstanceChangeSrc, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - - if newState.ManagedResourcesEqual(oldState) && moves.Changes.Len() == 0 { - // Nothing to do, because we only detect and report drift for managed - // resource instances. - return nil, diags - } - - schemas, schemaDiags := c.Schemas(config, newState) - diags = diags.Append(schemaDiags) - if diags.HasErrors() { - return nil, diags - } - - var drs []*plans.ResourceInstanceChangeSrc - - for _, ms := range oldState.Modules { - for _, rs := range ms.Resources { - if rs.Addr.Resource.Mode != addrs.ManagedResourceMode { - // Drift reporting is only for managed resources - continue - } - - provider := rs.ProviderConfig.Provider - for key, oldIS := range rs.Instances { - if oldIS.Current == nil { - // Not interested in instances that only have deposed objects - continue - } - addr := rs.Addr.Instance(key) - - // Previous run address defaults to the current address, but - // can differ if the resource moved before refreshing - prevRunAddr := addr - if move, ok := moves.Changes.GetOk(addr); ok { - prevRunAddr = move.From - } - - newIS := newState.ResourceInstance(addr) - - schema, _ := schemas.ResourceTypeConfig( - provider, - addr.Resource.Resource.Mode, - addr.Resource.Resource.Type, - ) - if schema == nil { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Warning, - "Missing resource schema from provider", - fmt.Sprintf("No resource schema found for %s when decoding prior state", addr.Resource.Resource.Type), - )) - continue - } - ty := schema.ImpliedType() - - oldObj, err := oldIS.Current.Decode(ty) - if err != nil { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Warning, - "Failed to decode resource from state", - fmt.Sprintf("Error decoding %q from prior state: %s", addr.String(), err), - )) - continue - } - - var newObj *states.ResourceInstanceObject - if newIS != nil && newIS.Current != nil { - newObj, err = newIS.Current.Decode(ty) - if err != nil { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Warning, - "Failed to decode resource from state", - fmt.Sprintf("Error decoding %q from prior state: %s", addr.String(), err), - )) - continue - } - } - - var oldVal, newVal cty.Value - oldVal = oldObj.Value - if newObj != nil { - newVal = newObj.Value - } else { - newVal = cty.NullVal(ty) - } - - if oldVal.RawEquals(newVal) && addr.Equal(prevRunAddr) { - // No drift if the two values are semantically equivalent - // and no move has happened - continue - } - - // We can detect three types of changes after refreshing state, - // only two of which are easily understood as "drift": - // - // - Resources which were deleted outside of Terraform; - // - Resources where the object value has changed outside of - // Terraform; - // - Resources which have been moved without other changes. - // - // All of these are returned as drift, to allow refresh-only plans - // to present a full set of changes which will be applied. - var action plans.Action - switch { - case newVal.IsNull(): - action = plans.Delete - case !oldVal.RawEquals(newVal): - action = plans.Update - default: - action = plans.NoOp - } - - change := &plans.ResourceInstanceChange{ - Addr: addr, - PrevRunAddr: prevRunAddr, - ProviderAddr: rs.ProviderConfig, - Change: plans.Change{ - Action: action, - Before: oldVal, - After: newVal, - }, - } - - changeSrc, err := change.Encode(ty) - if err != nil { - diags = diags.Append(err) - return nil, diags - } - - drs = append(drs, changeSrc) - } - } - } - - return drs, diags -} - -// PlanGraphForUI is a last vestage of graphs in the public interface of Context -// (as opposed to graphs as an implementation detail) intended only for use -// by the "terraform graph" command when asked to render a plan-time graph. -// -// The result of this is intended only for rendering ot the user as a dot -// graph, and so may change in future in order to make the result more useful -// in that context, even if drifts away from the physical graph that Terraform -// Core currently uses as an implementation detail of planning. -func (c *Context) PlanGraphForUI(config *configs.Config, prevRunState *states.State, mode plans.Mode) (*Graph, tfdiags.Diagnostics) { - // For now though, this really is just the internal graph, confusing - // implementation details and all. - - var diags tfdiags.Diagnostics - - opts := &PlanOpts{Mode: mode} - - graph, _, moreDiags := c.planGraph(config, prevRunState, opts) - diags = diags.Append(moreDiags) - return graph, diags -} - -func blockedMovesWarningDiag(results refactoring.MoveResults) tfdiags.Diagnostic { - if results.Blocked.Len() < 1 { - // Caller should check first - panic("request to render blocked moves warning without any blocked moves") - } - - var itemsBuf bytes.Buffer - for _, blocked := range results.Blocked.Values() { - fmt.Fprintf(&itemsBuf, "\n - %s could not move to %s", blocked.Actual, blocked.Wanted) - } - - return tfdiags.Sourceless( - tfdiags.Warning, - "Unresolved resource instance address changes", - fmt.Sprintf( - "Terraform tried to adjust resource instance addresses in the prior state based on change information recorded in the configuration, but some adjustments did not succeed due to existing objects already at the intended addresses:%s\n\nTerraform has planned to destroy these objects. If Terraform's proposed changes aren't appropriate, you must first resolve the conflicts using the \"terraform state\" subcommands and then create a new plan.", - itemsBuf.String(), - ), - ) -} - -// referenceAnalyzer returns a globalref.Analyzer object to help with -// global analysis of references within the configuration that's attached -// to the receiving context. -func (c *Context) referenceAnalyzer(config *configs.Config, state *states.State) (*globalref.Analyzer, tfdiags.Diagnostics) { - schemas, diags := c.Schemas(config, state) - if diags.HasErrors() { - return nil, diags - } - return globalref.NewAnalyzer(config, schemas.Providers), diags -} - -// relevantResourcesForPlan implements the heuristic we use to populate the -// RelevantResources field of returned plans. -func (c *Context) relevantResourceAttrsForPlan(config *configs.Config, plan *plans.Plan) ([]globalref.ResourceAttr, tfdiags.Diagnostics) { - azr, diags := c.referenceAnalyzer(config, plan.PriorState) - if diags.HasErrors() { - return nil, diags - } - - var refs []globalref.Reference - for _, change := range plan.Changes.Resources { - if change.Action == plans.NoOp { - continue - } - - moreRefs := azr.ReferencesFromResourceInstance(change.Addr) - refs = append(refs, moreRefs...) - } - - for _, change := range plan.Changes.Outputs { - if change.Action == plans.NoOp { - continue - } - - moreRefs := azr.ReferencesFromOutputValue(change.Addr) - refs = append(refs, moreRefs...) - } - - var contributors []globalref.ResourceAttr - - for _, ref := range azr.ContributingResourceReferences(refs...) { - if res, ok := ref.ResourceAttr(); ok { - contributors = append(contributors, res) - } - } - - return contributors, diags -} diff --git a/internal/terraform/context_plan2_test.go b/internal/terraform/context_plan2_test.go deleted file mode 100644 index 4e3d52f0793b..000000000000 --- a/internal/terraform/context_plan2_test.go +++ /dev/null @@ -1,4037 +0,0 @@ -package terraform - -import ( - "bytes" - "errors" - "fmt" - "strings" - "sync" - "testing" - - "github.com/davecgh/go-spew/spew" - "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/checks" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/lang/marks" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" - "github.com/zclconf/go-cty/cty" -) - -func TestContext2Plan_removedDuringRefresh(t *testing.T) { - // This tests the situation where an object tracked in the previous run - // state has been deleted outside of Terraform, which we should detect - // during the refresh step and thus ultimately produce a plan to recreate - // the object, since it's still present in the configuration. - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "test_object" "a" { -} -`, - }) - - p := simpleMockProvider() - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - Provider: providers.Schema{Block: simpleTestSchema()}, - ResourceTypes: map[string]providers.Schema{ - "test_object": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "arg": {Type: cty.String, Optional: true}, - }, - }, - }, - }, - } - p.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) { - resp.NewState = cty.NullVal(req.PriorState.Type()) - return resp - } - p.UpgradeResourceStateFn = func(req providers.UpgradeResourceStateRequest) (resp providers.UpgradeResourceStateResponse) { - // We should've been given the prior state JSON as our input to upgrade. - if !bytes.Contains(req.RawStateJSON, []byte("previous_run")) { - t.Fatalf("UpgradeResourceState request doesn't contain the previous run object\n%s", req.RawStateJSON) - } - - // We'll put something different in "arg" as part of upgrading, just - // so that we can verify below that PrevRunState contains the upgraded - // (but NOT refreshed) version of the object. - resp.UpgradedState = cty.ObjectVal(map[string]cty.Value{ - "arg": cty.StringVal("upgraded"), - }) - return resp - } - - addr := mustResourceInstanceAddr("test_object.a") - state := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{"arg":"previous_run"}`), - Status: states.ObjectTainted, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`)) - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - if !p.UpgradeResourceStateCalled { - t.Errorf("Provider's UpgradeResourceState wasn't called; should've been") - } - if !p.ReadResourceCalled { - t.Errorf("Provider's ReadResource wasn't called; should've been") - } - - // The object should be absent from the plan's prior state, because that - // records the result of refreshing. - if got := plan.PriorState.ResourceInstance(addr); got != nil { - t.Errorf( - "instance %s is in the prior state after planning; should've been removed\n%s", - addr, spew.Sdump(got), - ) - } - - // However, the object should still be in the PrevRunState, because - // that reflects what we believed to exist before refreshing. - if got := plan.PrevRunState.ResourceInstance(addr); got == nil { - t.Errorf( - "instance %s is missing from the previous run state after planning; should've been preserved", - addr, - ) - } else { - if !bytes.Contains(got.Current.AttrsJSON, []byte("upgraded")) { - t.Fatalf("previous run state has non-upgraded object\n%s", got.Current.AttrsJSON) - } - } - - // This situation should result in a drifted resource change. - var drifted *plans.ResourceInstanceChangeSrc - for _, dr := range plan.DriftedResources { - if dr.Addr.Equal(addr) { - drifted = dr - break - } - } - - if drifted == nil { - t.Errorf("instance %s is missing from the drifted resource changes", addr) - } else { - if got, want := drifted.Action, plans.Delete; got != want { - t.Errorf("unexpected instance %s drifted resource change action. got: %s, want: %s", addr, got, want) - } - } - - // Because the configuration still mentions test_object.a, we should've - // planned to recreate it in order to fix the drift. - for _, c := range plan.Changes.Resources { - if c.Action != plans.Create { - t.Fatalf("expected Create action for missing %s, got %s", c.Addr, c.Action) - } - } -} - -func TestContext2Plan_noChangeDataSourceSensitiveNestedSet(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -variable "bar" { - sensitive = true - default = "baz" -} - -data "test_data_source" "foo" { - foo { - bar = var.bar - } -} -`, - }) - - p := new(MockProvider) - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - DataSources: map[string]*configschema.Block{ - "test_data_source": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - }, - BlockTypes: map[string]*configschema.NestedBlock{ - "foo": { - Block: configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "bar": {Type: cty.String, Optional: true}, - }, - }, - Nesting: configschema.NestingSet, - }, - }, - }, - }, - }) - - p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{ - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("data_id"), - "foo": cty.SetVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{"bar": cty.StringVal("baz")})}), - }), - } - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("data.test_data_source.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"data_id", "foo":[{"bar":"baz"}]}`), - AttrSensitivePaths: []cty.PathValueMarks{ - { - Path: cty.GetAttrPath("foo"), - Marks: cty.NewValueMarks(marks.Sensitive), - }, - }, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))) - assertNoErrors(t, diags) - - for _, res := range plan.Changes.Resources { - if res.Action != plans.NoOp { - t.Fatalf("expected NoOp, got: %q %s", res.Addr, res.Action) - } - } -} - -func TestContext2Plan_orphanDataInstance(t *testing.T) { - // ensure the planned replacement of the data source is evaluated properly - m := testModuleInline(t, map[string]string{ - "main.tf": ` -data "test_object" "a" { - for_each = { new = "ok" } -} - -output "out" { - value = [ for k, _ in data.test_object.a: k ] -} -`, - }) - - p := simpleMockProvider() - p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) { - resp.State = req.Config - return resp - } - - state := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent(mustResourceInstanceAddr(`data.test_object.a["old"]`), &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{"test_string":"foo"}`), - Status: states.ObjectReady, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`)) - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - change, err := plan.Changes.Outputs[0].Decode() - if err != nil { - t.Fatal(err) - } - - expected := cty.TupleVal([]cty.Value{cty.StringVal("new")}) - - if change.After.Equals(expected).False() { - t.Fatalf("expected %#v, got %#v\n", expected, change.After) - } -} - -func TestContext2Plan_basicConfigurationAliases(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -provider "test" { - alias = "z" - test_string = "config" -} - -module "mod" { - source = "./mod" - providers = { - test.x = test.z - } -} -`, - - "mod/main.tf": ` -terraform { - required_providers { - test = { - source = "registry.terraform.io/hashicorp/test" - configuration_aliases = [ test.x ] - } - } -} - -resource "test_object" "a" { - provider = test.x -} - -`, - }) - - p := simpleMockProvider() - - // The resource within the module should be using the provider configured - // from the root module. We should never see an empty configuration. - p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) { - if req.Config.GetAttr("test_string").IsNull() { - resp.Diagnostics = resp.Diagnostics.Append(errors.New("missing test_string value")) - } - return resp - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - _, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) -} - -func TestContext2Plan_dataReferencesResourceInModules(t *testing.T) { - p := testProvider("test") - p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) { - cfg := req.Config.AsValueMap() - cfg["id"] = cty.StringVal("d") - resp.State = cty.ObjectVal(cfg) - return resp - } - - m := testModuleInline(t, map[string]string{ - "main.tf": ` -locals { - things = { - old = "first" - new = "second" - } -} - -module "mod" { - source = "./mod" - for_each = local.things -} -`, - - "./mod/main.tf": ` -resource "test_resource" "a" { -} - -data "test_data_source" "d" { - depends_on = [test_resource.a] -} - -resource "test_resource" "b" { - value = data.test_data_source.d.id -} -`}) - - oldDataAddr := mustResourceInstanceAddr(`module.mod["old"].data.test_data_source.d`) - - state := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent( - mustResourceInstanceAddr(`module.mod["old"].test_resource.a`), - &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{"id":"a"}`), - Status: states.ObjectReady, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - s.SetResourceInstanceCurrent( - mustResourceInstanceAddr(`module.mod["old"].test_resource.b`), - &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{"id":"b","value":"d"}`), - Status: states.ObjectReady, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - s.SetResourceInstanceCurrent( - oldDataAddr, - &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{"id":"d"}`), - Status: states.ObjectReady, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - oldMod := oldDataAddr.Module - - for _, c := range plan.Changes.Resources { - // there should be no changes from the old module instance - if c.Addr.Module.Equal(oldMod) && c.Action != plans.NoOp { - t.Errorf("unexpected change %s for %s\n", c.Action, c.Addr) - } - } -} - -func TestContext2Plan_resourceChecksInExpandedModule(t *testing.T) { - // When a resource is in a nested module we have two levels of expansion - // to do: first expand the module the resource is declared in, and then - // expand the resource itself. - // - // In earlier versions of Terraform we did that expansion as two levels - // of DynamicExpand, which led to a bug where we didn't have any central - // location from which to register all of the instances of a checkable - // resource. - // - // We now handle the full expansion all in one graph node and one dynamic - // subgraph, which avoids the problem. This is a regression test for the - // earlier bug. If this test is panicking with "duplicate checkable objects - // report" then that suggests the bug is reintroduced and we're now back - // to reporting each module instance separately again, which is incorrect. - - p := testProvider("test") - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - Provider: providers.Schema{ - Block: &configschema.Block{}, - }, - ResourceTypes: map[string]providers.Schema{ - "test": { - Block: &configschema.Block{}, - }, - }, - } - p.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) { - resp.NewState = req.PriorState - return resp - } - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { - resp.PlannedState = cty.EmptyObjectVal - return resp - } - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - resp.NewState = req.PlannedState - return resp - } - - m := testModuleInline(t, map[string]string{ - "main.tf": ` - module "child" { - source = "./child" - count = 2 # must be at least 2 for this test to be valid - } - `, - "child/child.tf": ` - locals { - a = "a" - } - - resource "test" "test1" { - lifecycle { - postcondition { - # It doesn't matter what this checks as long as it - # passes, because if we don't handle expansion properly - # then we'll crash before we even get to evaluating this. - condition = local.a == local.a - error_message = "Postcondition failed." - } - } - } - - resource "test" "test2" { - count = 2 - - lifecycle { - postcondition { - # It doesn't matter what this checks as long as it - # passes, because if we don't handle expansion properly - # then we'll crash before we even get to evaluating this. - condition = local.a == local.a - error_message = "Postcondition failed." - } - } - } - `, - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - priorState := states.NewState() - plan, diags := ctx.Plan(m, priorState, DefaultPlanOpts) - assertNoErrors(t, diags) - - resourceInsts := []addrs.AbsResourceInstance{ - mustResourceInstanceAddr("module.child[0].test.test1"), - mustResourceInstanceAddr("module.child[0].test.test2[0]"), - mustResourceInstanceAddr("module.child[0].test.test2[1]"), - mustResourceInstanceAddr("module.child[1].test.test1"), - mustResourceInstanceAddr("module.child[1].test.test2[0]"), - mustResourceInstanceAddr("module.child[1].test.test2[1]"), - } - - for _, instAddr := range resourceInsts { - t.Run(fmt.Sprintf("results for %s", instAddr), func(t *testing.T) { - if rc := plan.Changes.ResourceInstance(instAddr); rc != nil { - if got, want := rc.Action, plans.Create; got != want { - t.Errorf("wrong action for %s\ngot: %s\nwant: %s", instAddr, got, want) - } - if got, want := rc.ActionReason, plans.ResourceInstanceChangeNoReason; got != want { - t.Errorf("wrong action reason for %s\ngot: %s\nwant: %s", instAddr, got, want) - } - } else { - t.Errorf("no planned change for %s", instAddr) - } - - if checkResult := plan.Checks.GetObjectResult(instAddr); checkResult != nil { - if got, want := checkResult.Status, checks.StatusPass; got != want { - t.Errorf("wrong check status for %s\ngot: %s\nwant: %s", instAddr, got, want) - } - } else { - t.Errorf("no check result for %s", instAddr) - } - }) - } -} - -func TestContext2Plan_dataResourceChecksManagedResourceChange(t *testing.T) { - // This tests the situation where the remote system contains data that - // isn't valid per a data resource postcondition, but that the - // configuration is destined to make the remote system valid during apply - // and so we must defer reading the data resource and checking its - // conditions until the apply step. - // - // This is an exception to the rule tested in - // TestContext2Plan_dataReferencesResourceIndirectly which is relevant - // whenever there's at least one precondition or postcondition attached - // to a data resource. - // - // See TestContext2Plan_managedResourceChecksOtherManagedResourceChange for - // an incorrect situation where a data resource is used only indirectly - // to drive a precondition elsewhere, which therefore doesn't achieve this - // special exception. - - p := testProvider("test") - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - Provider: providers.Schema{ - Block: &configschema.Block{}, - }, - ResourceTypes: map[string]providers.Schema{ - "test_resource": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - "valid": { - Type: cty.Bool, - Required: true, - }, - }, - }, - }, - }, - DataSources: map[string]providers.Schema{ - "test_data_source": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Required: true, - }, - "valid": { - Type: cty.Bool, - Computed: true, - }, - }, - }, - }, - }, - } - var mu sync.Mutex - validVal := cty.False - p.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) { - // NOTE: This assumes that the prior state declared below will have - // "valid" set to false already, and thus will match validVal above. - resp.NewState = req.PriorState - return resp - } - p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) { - cfg := req.Config.AsValueMap() - mu.Lock() - cfg["valid"] = validVal - mu.Unlock() - resp.State = cty.ObjectVal(cfg) - return resp - } - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { - cfg := req.Config.AsValueMap() - prior := req.PriorState.AsValueMap() - resp.PlannedState = cty.ObjectVal(map[string]cty.Value{ - "id": prior["id"], - "valid": cfg["valid"], - }) - return resp - } - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - planned := req.PlannedState.AsValueMap() - - mu.Lock() - validVal = planned["valid"] - mu.Unlock() - - resp.NewState = req.PlannedState - return resp - } - - m := testModuleInline(t, map[string]string{ - "main.tf": ` - -resource "test_resource" "a" { - valid = true -} - -locals { - # NOTE: We intentionally read through a local value here to make sure - # that this behavior still works even if there isn't a direct dependency - # between the data resource and the managed resource. - object_id = test_resource.a.id -} - -data "test_data_source" "a" { - id = local.object_id - - lifecycle { - postcondition { - condition = self.valid - error_message = "Not valid!" - } - } -} -`}) - - managedAddr := mustResourceInstanceAddr(`test_resource.a`) - dataAddr := mustResourceInstanceAddr(`data.test_data_source.a`) - - // This state is intended to represent the outcome of a previous apply that - // failed due to postcondition failure but had already updated the - // relevant object to be invalid. - // - // It could also potentially represent a similar situation where the - // previous apply succeeded but there has been a change outside of - // Terraform that made it invalid, although technically in that scenario - // the state data would become invalid only during the planning step. For - // our purposes here that's close enough because we don't have a real - // remote system in place anyway. - priorState := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent( - managedAddr, - &states.ResourceInstanceObjectSrc{ - // NOTE: "valid" is false here but is true in the configuration - // above, which is intended to represent that applying the - // configuration change would make this object become valid. - AttrsJSON: []byte(`{"id":"boop","valid":false}`), - Status: states.ObjectReady, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, priorState, DefaultPlanOpts) - assertNoErrors(t, diags) - - if rc := plan.Changes.ResourceInstance(dataAddr); rc != nil { - if got, want := rc.Action, plans.Read; got != want { - t.Errorf("wrong action for %s\ngot: %s\nwant: %s", dataAddr, got, want) - } - if got, want := rc.ActionReason, plans.ResourceInstanceReadBecauseDependencyPending; got != want { - t.Errorf("wrong action reason for %s\ngot: %s\nwant: %s", dataAddr, got, want) - } - } else { - t.Fatalf("no planned change for %s", dataAddr) - } - - if rc := plan.Changes.ResourceInstance(managedAddr); rc != nil { - if got, want := rc.Action, plans.Update; got != want { - t.Errorf("wrong action for %s\ngot: %s\nwant: %s", managedAddr, got, want) - } - if got, want := rc.ActionReason, plans.ResourceInstanceChangeNoReason; got != want { - t.Errorf("wrong action reason for %s\ngot: %s\nwant: %s", managedAddr, got, want) - } - } else { - t.Fatalf("no planned change for %s", managedAddr) - } - - // This is primarily a plan-time test, since the special handling of - // data resources is a plan-time concern, but we'll still try applying the - // plan here just to make sure it's valid. - newState, diags := ctx.Apply(plan, m) - assertNoErrors(t, diags) - - if rs := newState.ResourceInstance(dataAddr); rs != nil { - if !rs.HasCurrent() { - t.Errorf("no final state for %s", dataAddr) - } - } else { - t.Errorf("no final state for %s", dataAddr) - } - - if rs := newState.ResourceInstance(managedAddr); rs != nil { - if !rs.HasCurrent() { - t.Errorf("no final state for %s", managedAddr) - } - } else { - t.Errorf("no final state for %s", managedAddr) - } - - if got, want := validVal, cty.True; got != want { - t.Errorf("wrong final valid value\ngot: %#v\nwant: %#v", got, want) - } - -} - -func TestContext2Plan_managedResourceChecksOtherManagedResourceChange(t *testing.T) { - // This tests the incorrect situation where a managed resource checks - // another managed resource indirectly via a data resource. - // This doesn't work because Terraform can't tell that the data resource - // outcome will be updated by a separate managed resource change and so - // we expect it to fail. - // This would ideally have worked except that we previously included a - // special case in the rules for data resources where they only consider - // direct dependencies when deciding whether to defer (except when the - // data resource itself has conditions) and so they can potentially - // read "too early" if the user creates the explicitly-not-recommended - // situation of a data resource and a managed resource in the same - // configuration both representing the same remote object. - - p := testProvider("test") - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - Provider: providers.Schema{ - Block: &configschema.Block{}, - }, - ResourceTypes: map[string]providers.Schema{ - "test_resource": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - "valid": { - Type: cty.Bool, - Required: true, - }, - }, - }, - }, - }, - DataSources: map[string]providers.Schema{ - "test_data_source": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Required: true, - }, - "valid": { - Type: cty.Bool, - Computed: true, - }, - }, - }, - }, - }, - } - var mu sync.Mutex - validVal := cty.False - p.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) { - // NOTE: This assumes that the prior state declared below will have - // "valid" set to false already, and thus will match validVal above. - resp.NewState = req.PriorState - return resp - } - p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) { - cfg := req.Config.AsValueMap() - if cfg["id"].AsString() == "main" { - mu.Lock() - cfg["valid"] = validVal - mu.Unlock() - } - resp.State = cty.ObjectVal(cfg) - return resp - } - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { - cfg := req.Config.AsValueMap() - prior := req.PriorState.AsValueMap() - resp.PlannedState = cty.ObjectVal(map[string]cty.Value{ - "id": prior["id"], - "valid": cfg["valid"], - }) - return resp - } - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - planned := req.PlannedState.AsValueMap() - - if planned["id"].AsString() == "main" { - mu.Lock() - validVal = planned["valid"] - mu.Unlock() - } - - resp.NewState = req.PlannedState - return resp - } - - m := testModuleInline(t, map[string]string{ - "main.tf": ` - -resource "test_resource" "a" { - valid = true -} - -locals { - # NOTE: We intentionally read through a local value here because a - # direct reference from data.test_data_source.a to test_resource.a would - # cause Terraform to defer the data resource to the apply phase due to - # there being a pending change for the managed resource. We're explicitly - # testing the failure case where the data resource read happens too - # eagerly, which is what results from the reference being only indirect - # so Terraform can't "see" that the data resource result might be affected - # by changes to the managed resource. - object_id = test_resource.a.id -} - -data "test_data_source" "a" { - id = local.object_id -} - -resource "test_resource" "b" { - valid = true - - lifecycle { - precondition { - condition = data.test_data_source.a.valid - error_message = "Not valid!" - } - } -} -`}) - - managedAddrA := mustResourceInstanceAddr(`test_resource.a`) - managedAddrB := mustResourceInstanceAddr(`test_resource.b`) - - // This state is intended to represent the outcome of a previous apply that - // failed due to postcondition failure but had already updated the - // relevant object to be invalid. - // - // It could also potentially represent a similar situation where the - // previous apply succeeded but there has been a change outside of - // Terraform that made it invalid, although technically in that scenario - // the state data would become invalid only during the planning step. For - // our purposes here that's close enough because we don't have a real - // remote system in place anyway. - priorState := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent( - managedAddrA, - &states.ResourceInstanceObjectSrc{ - // NOTE: "valid" is false here but is true in the configuration - // above, which is intended to represent that applying the - // configuration change would make this object become valid. - AttrsJSON: []byte(`{"id":"main","valid":false}`), - Status: states.ObjectReady, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - s.SetResourceInstanceCurrent( - managedAddrB, - &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{"id":"checker","valid":true}`), - Status: states.ObjectReady, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - _, diags := ctx.Plan(m, priorState, DefaultPlanOpts) - if !diags.HasErrors() { - t.Fatalf("unexpected successful plan; should've failed with non-passing precondition") - } - - if got, want := diags.Err().Error(), "Resource precondition failed: Not valid!"; !strings.Contains(got, want) { - t.Errorf("Missing expected error message\ngot: %s\nwant substring: %s", got, want) - } -} - -func TestContext2Plan_destroyWithRefresh(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "test_object" "a" { -} -`, - }) - - p := simpleMockProvider() - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - Provider: providers.Schema{Block: simpleTestSchema()}, - ResourceTypes: map[string]providers.Schema{ - "test_object": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "arg": {Type: cty.String, Optional: true}, - }, - }, - }, - }, - } - - // This is called from the first instance of this provider, so we can't - // check p.ReadResourceCalled after plan. - readResourceCalled := false - p.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) { - readResourceCalled = true - newVal, err := cty.Transform(req.PriorState, func(path cty.Path, v cty.Value) (cty.Value, error) { - if len(path) == 1 && path[0] == (cty.GetAttrStep{Name: "arg"}) { - return cty.StringVal("current"), nil - } - return v, nil - }) - if err != nil { - // shouldn't get here - t.Fatalf("ReadResourceFn transform failed") - return providers.ReadResourceResponse{} - } - return providers.ReadResourceResponse{ - NewState: newVal, - } - } - - upgradeResourceStateCalled := false - p.UpgradeResourceStateFn = func(req providers.UpgradeResourceStateRequest) (resp providers.UpgradeResourceStateResponse) { - upgradeResourceStateCalled = true - t.Logf("UpgradeResourceState %s", req.RawStateJSON) - - // In the destroy-with-refresh codepath we end up calling - // UpgradeResourceState twice, because we do so once during refreshing - // (as part making a normal plan) and then again during the plan-destroy - // walk. The second call recieves the result of the earlier refresh, - // so we need to tolerate both "before" and "current" as possible - // inputs here. - if !bytes.Contains(req.RawStateJSON, []byte("before")) { - if !bytes.Contains(req.RawStateJSON, []byte("current")) { - t.Fatalf("UpgradeResourceState request doesn't contain the 'before' object or the 'current' object\n%s", req.RawStateJSON) - } - } - - // We'll put something different in "arg" as part of upgrading, just - // so that we can verify below that PrevRunState contains the upgraded - // (but NOT refreshed) version of the object. - resp.UpgradedState = cty.ObjectVal(map[string]cty.Value{ - "arg": cty.StringVal("upgraded"), - }) - return resp - } - - addr := mustResourceInstanceAddr("test_object.a") - state := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{"arg":"before"}`), - Status: states.ObjectReady, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`)) - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - SkipRefresh: false, // the default - }) - assertNoErrors(t, diags) - - if !upgradeResourceStateCalled { - t.Errorf("Provider's UpgradeResourceState wasn't called; should've been") - } - if !readResourceCalled { - t.Errorf("Provider's ReadResource wasn't called; should've been") - } - - if plan.PriorState == nil { - t.Fatal("missing plan state") - } - - for _, c := range plan.Changes.Resources { - if c.Action != plans.Delete { - t.Errorf("unexpected %s change for %s", c.Action, c.Addr) - } - } - - if instState := plan.PrevRunState.ResourceInstance(addr); instState == nil { - t.Errorf("%s has no previous run state at all after plan", addr) - } else { - if instState.Current == nil { - t.Errorf("%s has no current object in the previous run state", addr) - } else if got, want := instState.Current.AttrsJSON, `"upgraded"`; !bytes.Contains(got, []byte(want)) { - t.Errorf("%s has wrong previous run state after plan\ngot:\n%s\n\nwant substring: %s", addr, got, want) - } - } - if instState := plan.PriorState.ResourceInstance(addr); instState == nil { - t.Errorf("%s has no prior state at all after plan", addr) - } else { - if instState.Current == nil { - t.Errorf("%s has no current object in the prior state", addr) - } else if got, want := instState.Current.AttrsJSON, `"current"`; !bytes.Contains(got, []byte(want)) { - t.Errorf("%s has wrong prior state after plan\ngot:\n%s\n\nwant substring: %s", addr, got, want) - } - } -} - -func TestContext2Plan_destroySkipRefresh(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "test_object" "a" { -} -`, - }) - - p := simpleMockProvider() - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - Provider: providers.Schema{Block: simpleTestSchema()}, - ResourceTypes: map[string]providers.Schema{ - "test_object": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "arg": {Type: cty.String, Optional: true}, - }, - }, - }, - }, - } - p.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) { - t.Helper() - t.Errorf("unexpected call to ReadResource") - resp.NewState = req.PriorState - return resp - } - p.UpgradeResourceStateFn = func(req providers.UpgradeResourceStateRequest) (resp providers.UpgradeResourceStateResponse) { - t.Logf("UpgradeResourceState %s", req.RawStateJSON) - // We should've been given the prior state JSON as our input to upgrade. - if !bytes.Contains(req.RawStateJSON, []byte("before")) { - t.Fatalf("UpgradeResourceState request doesn't contain the 'before' object\n%s", req.RawStateJSON) - } - - // We'll put something different in "arg" as part of upgrading, just - // so that we can verify below that PrevRunState contains the upgraded - // (but NOT refreshed) version of the object. - resp.UpgradedState = cty.ObjectVal(map[string]cty.Value{ - "arg": cty.StringVal("upgraded"), - }) - return resp - } - - addr := mustResourceInstanceAddr("test_object.a") - state := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{"arg":"before"}`), - Status: states.ObjectReady, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`)) - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - SkipRefresh: true, - }) - assertNoErrors(t, diags) - - if !p.UpgradeResourceStateCalled { - t.Errorf("Provider's UpgradeResourceState wasn't called; should've been") - } - if p.ReadResourceCalled { - t.Errorf("Provider's ReadResource was called; shouldn't have been") - } - - if plan.PriorState == nil { - t.Fatal("missing plan state") - } - - for _, c := range plan.Changes.Resources { - if c.Action != plans.Delete { - t.Errorf("unexpected %s change for %s", c.Action, c.Addr) - } - } - - if instState := plan.PrevRunState.ResourceInstance(addr); instState == nil { - t.Errorf("%s has no previous run state at all after plan", addr) - } else { - if instState.Current == nil { - t.Errorf("%s has no current object in the previous run state", addr) - } else if got, want := instState.Current.AttrsJSON, `"upgraded"`; !bytes.Contains(got, []byte(want)) { - t.Errorf("%s has wrong previous run state after plan\ngot:\n%s\n\nwant substring: %s", addr, got, want) - } - } - if instState := plan.PriorState.ResourceInstance(addr); instState == nil { - t.Errorf("%s has no prior state at all after plan", addr) - } else { - if instState.Current == nil { - t.Errorf("%s has no current object in the prior state", addr) - } else if got, want := instState.Current.AttrsJSON, `"upgraded"`; !bytes.Contains(got, []byte(want)) { - // NOTE: The prior state should still have been _upgraded_, even - // though we skipped running refresh after upgrading it. - t.Errorf("%s has wrong prior state after plan\ngot:\n%s\n\nwant substring: %s", addr, got, want) - } - } -} - -func TestContext2Plan_unmarkingSensitiveAttributeForOutput(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "test_resource" "foo" { -} - -output "result" { - value = nonsensitive(test_resource.foo.sensitive_attr) -} -`, - }) - - p := new(MockProvider) - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test_resource": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - "sensitive_attr": { - Type: cty.String, - Computed: true, - Sensitive: true, - }, - }, - }, - }, - }) - - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse { - return providers.PlanResourceChangeResponse{ - PlannedState: cty.UnknownVal(cty.Object(map[string]cty.Type{ - "id": cty.String, - "sensitive_attr": cty.String, - })), - } - } - - state := states.NewState() - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - for _, res := range plan.Changes.Resources { - if res.Action != plans.Create { - t.Fatalf("expected create, got: %q %s", res.Addr, res.Action) - } - } -} - -func TestContext2Plan_destroyNoProviderConfig(t *testing.T) { - // providers do not need to be configured during a destroy plan - p := simpleMockProvider() - p.ValidateProviderConfigFn = func(req providers.ValidateProviderConfigRequest) (resp providers.ValidateProviderConfigResponse) { - v := req.Config.GetAttr("test_string") - if v.IsNull() || !v.IsKnown() || v.AsString() != "ok" { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("invalid provider configuration: %#v", req.Config)) - } - return resp - } - - m := testModuleInline(t, map[string]string{ - "main.tf": ` -locals { - value = "ok" -} - -provider "test" { - test_string = local.value -} -`, - }) - - addr := mustResourceInstanceAddr("test_object.a") - state := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{"test_string":"foo"}`), - Status: states.ObjectReady, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`)) - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - _, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - assertNoErrors(t, diags) -} - -func TestContext2Plan_movedResourceBasic(t *testing.T) { - addrA := mustResourceInstanceAddr("test_object.a") - addrB := mustResourceInstanceAddr("test_object.b") - m := testModuleInline(t, map[string]string{ - "main.tf": ` - resource "test_object" "b" { - } - - moved { - from = test_object.a - to = test_object.b - } - `, - }) - - state := states.BuildState(func(s *states.SyncState) { - // The prior state tracks test_object.a, which we should treat as - // test_object.b because of the "moved" block in the config. - s.SetResourceInstanceCurrent(addrA, &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{}`), - Status: states.ObjectReady, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`)) - }) - - p := simpleMockProvider() - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.NormalMode, - ForceReplace: []addrs.AbsResourceInstance{ - addrA, - }, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors\n%s", diags.Err().Error()) - } - - t.Run(addrA.String(), func(t *testing.T) { - instPlan := plan.Changes.ResourceInstance(addrA) - if instPlan != nil { - t.Fatalf("unexpected plan for %s; should've moved to %s", addrA, addrB) - } - }) - t.Run(addrB.String(), func(t *testing.T) { - instPlan := plan.Changes.ResourceInstance(addrB) - if instPlan == nil { - t.Fatalf("no plan for %s at all", addrB) - } - - if got, want := instPlan.Addr, addrB; !got.Equal(want) { - t.Errorf("wrong current address\ngot: %s\nwant: %s", got, want) - } - if got, want := instPlan.PrevRunAddr, addrA; !got.Equal(want) { - t.Errorf("wrong previous run address\ngot: %s\nwant: %s", got, want) - } - if got, want := instPlan.Action, plans.NoOp; got != want { - t.Errorf("wrong planned action\ngot: %s\nwant: %s", got, want) - } - if got, want := instPlan.ActionReason, plans.ResourceInstanceChangeNoReason; got != want { - t.Errorf("wrong action reason\ngot: %s\nwant: %s", got, want) - } - }) -} - -func TestContext2Plan_movedResourceCollision(t *testing.T) { - addrNoKey := mustResourceInstanceAddr("test_object.a") - addrZeroKey := mustResourceInstanceAddr("test_object.a[0]") - m := testModuleInline(t, map[string]string{ - "main.tf": ` - resource "test_object" "a" { - # No "count" set, so test_object.a[0] will want - # to implicitly move to test_object.a, but will get - # blocked by the existing object at that address. - } - `, - }) - - state := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent(addrNoKey, &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{}`), - Status: states.ObjectReady, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`)) - s.SetResourceInstanceCurrent(addrZeroKey, &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{}`), - Status: states.ObjectReady, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`)) - }) - - p := simpleMockProvider() - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.NormalMode, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors\n%s", diags.Err().Error()) - } - - // We should have a warning, though! We'll lightly abuse the "for RPC" - // feature of diagnostics to get some more-readily-comparable diagnostic - // values. - gotDiags := diags.ForRPC() - wantDiags := tfdiags.Diagnostics{ - tfdiags.Sourceless( - tfdiags.Warning, - "Unresolved resource instance address changes", - `Terraform tried to adjust resource instance addresses in the prior state based on change information recorded in the configuration, but some adjustments did not succeed due to existing objects already at the intended addresses: - - test_object.a[0] could not move to test_object.a - -Terraform has planned to destroy these objects. If Terraform's proposed changes aren't appropriate, you must first resolve the conflicts using the "terraform state" subcommands and then create a new plan.`, - ), - }.ForRPC() - if diff := cmp.Diff(wantDiags, gotDiags); diff != "" { - t.Errorf("wrong diagnostics\n%s", diff) - } - - t.Run(addrNoKey.String(), func(t *testing.T) { - instPlan := plan.Changes.ResourceInstance(addrNoKey) - if instPlan == nil { - t.Fatalf("no plan for %s at all", addrNoKey) - } - - if got, want := instPlan.Addr, addrNoKey; !got.Equal(want) { - t.Errorf("wrong current address\ngot: %s\nwant: %s", got, want) - } - if got, want := instPlan.PrevRunAddr, addrNoKey; !got.Equal(want) { - t.Errorf("wrong previous run address\ngot: %s\nwant: %s", got, want) - } - if got, want := instPlan.Action, plans.NoOp; got != want { - t.Errorf("wrong planned action\ngot: %s\nwant: %s", got, want) - } - if got, want := instPlan.ActionReason, plans.ResourceInstanceChangeNoReason; got != want { - t.Errorf("wrong action reason\ngot: %s\nwant: %s", got, want) - } - }) - t.Run(addrZeroKey.String(), func(t *testing.T) { - instPlan := plan.Changes.ResourceInstance(addrZeroKey) - if instPlan == nil { - t.Fatalf("no plan for %s at all", addrZeroKey) - } - - if got, want := instPlan.Addr, addrZeroKey; !got.Equal(want) { - t.Errorf("wrong current address\ngot: %s\nwant: %s", got, want) - } - if got, want := instPlan.PrevRunAddr, addrZeroKey; !got.Equal(want) { - t.Errorf("wrong previous run address\ngot: %s\nwant: %s", got, want) - } - if got, want := instPlan.Action, plans.Delete; got != want { - t.Errorf("wrong planned action\ngot: %s\nwant: %s", got, want) - } - if got, want := instPlan.ActionReason, plans.ResourceInstanceDeleteBecauseWrongRepetition; got != want { - t.Errorf("wrong action reason\ngot: %s\nwant: %s", got, want) - } - }) -} - -func TestContext2Plan_movedResourceCollisionDestroy(t *testing.T) { - // This is like TestContext2Plan_movedResourceCollision but intended to - // ensure we still produce the expected warning (and produce it only once) - // when we're creating a destroy plan, rather than a normal plan. - // (This case is interesting at the time of writing because we happen to - // use a normal plan as a trick to refresh before creating a destroy plan. - // This test will probably become uninteresting if a future change to - // the destroy-time planning behavior handles refreshing in a different - // way, which avoids this pre-processing step of running a normal plan - // first.) - - addrNoKey := mustResourceInstanceAddr("test_object.a") - addrZeroKey := mustResourceInstanceAddr("test_object.a[0]") - m := testModuleInline(t, map[string]string{ - "main.tf": ` - resource "test_object" "a" { - # No "count" set, so test_object.a[0] will want - # to implicitly move to test_object.a, but will get - # blocked by the existing object at that address. - } - `, - }) - - state := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent(addrNoKey, &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{}`), - Status: states.ObjectReady, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`)) - s.SetResourceInstanceCurrent(addrZeroKey, &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{}`), - Status: states.ObjectReady, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`)) - }) - - p := simpleMockProvider() - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors\n%s", diags.Err().Error()) - } - - // We should have a warning, though! We'll lightly abuse the "for RPC" - // feature of diagnostics to get some more-readily-comparable diagnostic - // values. - gotDiags := diags.ForRPC() - wantDiags := tfdiags.Diagnostics{ - tfdiags.Sourceless( - tfdiags.Warning, - "Unresolved resource instance address changes", - // NOTE: This message is _lightly_ confusing in the destroy case, - // because it says "Terraform has planned to destroy these objects" - // but this is a plan to destroy all objects, anyway. We expect the - // conflict situation to be pretty rare though, and even rarer in - // a "terraform destroy", so we'll just live with that for now - // unless we see evidence that lots of folks are being confused by - // it in practice. - `Terraform tried to adjust resource instance addresses in the prior state based on change information recorded in the configuration, but some adjustments did not succeed due to existing objects already at the intended addresses: - - test_object.a[0] could not move to test_object.a - -Terraform has planned to destroy these objects. If Terraform's proposed changes aren't appropriate, you must first resolve the conflicts using the "terraform state" subcommands and then create a new plan.`, - ), - }.ForRPC() - if diff := cmp.Diff(wantDiags, gotDiags); diff != "" { - // If we get here with a diff that makes it seem like the above warning - // is being reported twice, the likely cause is not correctly handling - // the warnings from the hidden normal plan we run as part of preparing - // for a destroy plan, unless that strategy has changed in the meantime - // since we originally wrote this test. - t.Errorf("wrong diagnostics\n%s", diff) - } - - t.Run(addrNoKey.String(), func(t *testing.T) { - instPlan := plan.Changes.ResourceInstance(addrNoKey) - if instPlan == nil { - t.Fatalf("no plan for %s at all", addrNoKey) - } - - if got, want := instPlan.Addr, addrNoKey; !got.Equal(want) { - t.Errorf("wrong current address\ngot: %s\nwant: %s", got, want) - } - if got, want := instPlan.PrevRunAddr, addrNoKey; !got.Equal(want) { - t.Errorf("wrong previous run address\ngot: %s\nwant: %s", got, want) - } - if got, want := instPlan.Action, plans.Delete; got != want { - t.Errorf("wrong planned action\ngot: %s\nwant: %s", got, want) - } - if got, want := instPlan.ActionReason, plans.ResourceInstanceChangeNoReason; got != want { - t.Errorf("wrong action reason\ngot: %s\nwant: %s", got, want) - } - }) - t.Run(addrZeroKey.String(), func(t *testing.T) { - instPlan := plan.Changes.ResourceInstance(addrZeroKey) - if instPlan == nil { - t.Fatalf("no plan for %s at all", addrZeroKey) - } - - if got, want := instPlan.Addr, addrZeroKey; !got.Equal(want) { - t.Errorf("wrong current address\ngot: %s\nwant: %s", got, want) - } - if got, want := instPlan.PrevRunAddr, addrZeroKey; !got.Equal(want) { - t.Errorf("wrong previous run address\ngot: %s\nwant: %s", got, want) - } - if got, want := instPlan.Action, plans.Delete; got != want { - t.Errorf("wrong planned action\ngot: %s\nwant: %s", got, want) - } - if got, want := instPlan.ActionReason, plans.ResourceInstanceChangeNoReason; got != want { - t.Errorf("wrong action reason\ngot: %s\nwant: %s", got, want) - } - }) -} - -func TestContext2Plan_movedResourceUntargeted(t *testing.T) { - addrA := mustResourceInstanceAddr("test_object.a") - addrB := mustResourceInstanceAddr("test_object.b") - m := testModuleInline(t, map[string]string{ - "main.tf": ` - resource "test_object" "b" { - } - - moved { - from = test_object.a - to = test_object.b - } - `, - }) - - state := states.BuildState(func(s *states.SyncState) { - // The prior state tracks test_object.a, which we should treat as - // test_object.b because of the "moved" block in the config. - s.SetResourceInstanceCurrent(addrA, &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{}`), - Status: states.ObjectReady, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`)) - }) - - p := simpleMockProvider() - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - t.Run("without targeting instance A", func(t *testing.T) { - _, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.NormalMode, - Targets: []addrs.Targetable{ - // NOTE: addrA isn't included here, but it's pending move to addrB - // and so this plan request is invalid. - addrB, - }, - }) - diags.Sort() - - // We're semi-abusing "ForRPC" here just to get diagnostics that are - // more easily comparable than the various different diagnostics types - // tfdiags uses internally. The RPC-friendly diagnostics are also - // comparison-friendly, by discarding all of the dynamic type information. - gotDiags := diags.ForRPC() - wantDiags := tfdiags.Diagnostics{ - tfdiags.Sourceless( - tfdiags.Warning, - "Resource targeting is in effect", - `You are creating a plan with the -target option, which means that the result of this plan may not represent all of the changes requested by the current configuration. - -The -target option is not for routine use, and is provided only for exceptional situations such as recovering from errors or mistakes, or when Terraform specifically suggests to use it as part of an error message.`, - ), - tfdiags.Sourceless( - tfdiags.Error, - "Moved resource instances excluded by targeting", - `Resource instances in your current state have moved to new addresses in the latest configuration. Terraform must include those resource instances while planning in order to ensure a correct result, but your -target=... options to not fully cover all of those resource instances. - -To create a valid plan, either remove your -target=... options altogether or add the following additional target options: - -target="test_object.a" - -Note that adding these options may include further additional resource instances in your plan, in order to respect object dependencies.`, - ), - }.ForRPC() - - if diff := cmp.Diff(wantDiags, gotDiags); diff != "" { - t.Errorf("wrong diagnostics\n%s", diff) - } - }) - t.Run("without targeting instance B", func(t *testing.T) { - _, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.NormalMode, - Targets: []addrs.Targetable{ - addrA, - // NOTE: addrB isn't included here, but it's pending move from - // addrA and so this plan request is invalid. - }, - }) - diags.Sort() - - // We're semi-abusing "ForRPC" here just to get diagnostics that are - // more easily comparable than the various different diagnostics types - // tfdiags uses internally. The RPC-friendly diagnostics are also - // comparison-friendly, by discarding all of the dynamic type information. - gotDiags := diags.ForRPC() - wantDiags := tfdiags.Diagnostics{ - tfdiags.Sourceless( - tfdiags.Warning, - "Resource targeting is in effect", - `You are creating a plan with the -target option, which means that the result of this plan may not represent all of the changes requested by the current configuration. - -The -target option is not for routine use, and is provided only for exceptional situations such as recovering from errors or mistakes, or when Terraform specifically suggests to use it as part of an error message.`, - ), - tfdiags.Sourceless( - tfdiags.Error, - "Moved resource instances excluded by targeting", - `Resource instances in your current state have moved to new addresses in the latest configuration. Terraform must include those resource instances while planning in order to ensure a correct result, but your -target=... options to not fully cover all of those resource instances. - -To create a valid plan, either remove your -target=... options altogether or add the following additional target options: - -target="test_object.b" - -Note that adding these options may include further additional resource instances in your plan, in order to respect object dependencies.`, - ), - }.ForRPC() - - if diff := cmp.Diff(wantDiags, gotDiags); diff != "" { - t.Errorf("wrong diagnostics\n%s", diff) - } - }) - t.Run("without targeting either instance", func(t *testing.T) { - _, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.NormalMode, - Targets: []addrs.Targetable{ - mustResourceInstanceAddr("test_object.unrelated"), - // NOTE: neither addrA nor addrB are included here, but there's - // a pending move between them and so this is invalid. - }, - }) - diags.Sort() - - // We're semi-abusing "ForRPC" here just to get diagnostics that are - // more easily comparable than the various different diagnostics types - // tfdiags uses internally. The RPC-friendly diagnostics are also - // comparison-friendly, by discarding all of the dynamic type information. - gotDiags := diags.ForRPC() - wantDiags := tfdiags.Diagnostics{ - tfdiags.Sourceless( - tfdiags.Warning, - "Resource targeting is in effect", - `You are creating a plan with the -target option, which means that the result of this plan may not represent all of the changes requested by the current configuration. - -The -target option is not for routine use, and is provided only for exceptional situations such as recovering from errors or mistakes, or when Terraform specifically suggests to use it as part of an error message.`, - ), - tfdiags.Sourceless( - tfdiags.Error, - "Moved resource instances excluded by targeting", - `Resource instances in your current state have moved to new addresses in the latest configuration. Terraform must include those resource instances while planning in order to ensure a correct result, but your -target=... options to not fully cover all of those resource instances. - -To create a valid plan, either remove your -target=... options altogether or add the following additional target options: - -target="test_object.a" - -target="test_object.b" - -Note that adding these options may include further additional resource instances in your plan, in order to respect object dependencies.`, - ), - }.ForRPC() - - if diff := cmp.Diff(wantDiags, gotDiags); diff != "" { - t.Errorf("wrong diagnostics\n%s", diff) - } - }) - t.Run("with both addresses in the target set", func(t *testing.T) { - // The error messages in the other subtests above suggest adding - // addresses to the set of targets. This additional test makes sure that - // following that advice actually leads to a valid result. - - _, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.NormalMode, - Targets: []addrs.Targetable{ - // This time we're including both addresses in the target, - // to get the same effect an end-user would get if following - // the advice in our error message in the other subtests. - addrA, - addrB, - }, - }) - diags.Sort() - - // We're semi-abusing "ForRPC" here just to get diagnostics that are - // more easily comparable than the various different diagnostics types - // tfdiags uses internally. The RPC-friendly diagnostics are also - // comparison-friendly, by discarding all of the dynamic type information. - gotDiags := diags.ForRPC() - wantDiags := tfdiags.Diagnostics{ - // Still get the warning about the -target option... - tfdiags.Sourceless( - tfdiags.Warning, - "Resource targeting is in effect", - `You are creating a plan with the -target option, which means that the result of this plan may not represent all of the changes requested by the current configuration. - -The -target option is not for routine use, and is provided only for exceptional situations such as recovering from errors or mistakes, or when Terraform specifically suggests to use it as part of an error message.`, - ), - // ...but now we have no error about test_object.a - }.ForRPC() - - if diff := cmp.Diff(wantDiags, gotDiags); diff != "" { - t.Errorf("wrong diagnostics\n%s", diff) - } - }) -} - -func TestContext2Plan_untargetedResourceSchemaChange(t *testing.T) { - // an untargeted resource which requires a schema migration should not - // block planning due external changes in the plan. - addrA := mustResourceInstanceAddr("test_object.a") - addrB := mustResourceInstanceAddr("test_object.b") - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "test_object" "a" { -} -resource "test_object" "b" { -}`, - }) - - state := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent(addrA, &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{}`), - Status: states.ObjectReady, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`)) - s.SetResourceInstanceCurrent(addrB, &states.ResourceInstanceObjectSrc{ - // old_list is no longer in the schema - AttrsJSON: []byte(`{"old_list":["used to be","a list here"]}`), - Status: states.ObjectReady, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`)) - }) - - p := simpleMockProvider() - - // external changes trigger a "drift report", but because test_object.b was - // not targeted, the state was not fixed to match the schema and cannot be - // deocded for the report. - p.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) { - obj := req.PriorState.AsValueMap() - // test_number changed externally - obj["test_number"] = cty.NumberIntVal(1) - resp.NewState = cty.ObjectVal(obj) - return resp - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - _, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.NormalMode, - Targets: []addrs.Targetable{ - addrA, - }, - }) - // - assertNoErrors(t, diags) -} - -func TestContext2Plan_movedResourceRefreshOnly(t *testing.T) { - addrA := mustResourceInstanceAddr("test_object.a") - addrB := mustResourceInstanceAddr("test_object.b") - m := testModuleInline(t, map[string]string{ - "main.tf": ` - resource "test_object" "b" { - } - - moved { - from = test_object.a - to = test_object.b - } - `, - }) - - state := states.BuildState(func(s *states.SyncState) { - // The prior state tracks test_object.a, which we should treat as - // test_object.b because of the "moved" block in the config. - s.SetResourceInstanceCurrent(addrA, &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{}`), - Status: states.ObjectReady, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`)) - }) - - p := simpleMockProvider() - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.RefreshOnlyMode, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors\n%s", diags.Err().Error()) - } - - t.Run(addrA.String(), func(t *testing.T) { - instPlan := plan.Changes.ResourceInstance(addrA) - if instPlan != nil { - t.Fatalf("unexpected plan for %s; should've moved to %s", addrA, addrB) - } - }) - t.Run(addrB.String(), func(t *testing.T) { - instPlan := plan.Changes.ResourceInstance(addrB) - if instPlan != nil { - t.Fatalf("unexpected plan for %s", addrB) - } - }) - t.Run("drift", func(t *testing.T) { - var drifted *plans.ResourceInstanceChangeSrc - for _, dr := range plan.DriftedResources { - if dr.Addr.Equal(addrB) { - drifted = dr - break - } - } - - if drifted == nil { - t.Fatalf("instance %s is missing from the drifted resource changes", addrB) - } - - if got, want := drifted.PrevRunAddr, addrA; !got.Equal(want) { - t.Errorf("wrong previous run address\ngot: %s\nwant: %s", got, want) - } - if got, want := drifted.Action, plans.NoOp; got != want { - t.Errorf("wrong planned action\ngot: %s\nwant: %s", got, want) - } - }) -} - -func TestContext2Plan_refreshOnlyMode(t *testing.T) { - addr := mustResourceInstanceAddr("test_object.a") - - // The configuration, the prior state, and the refresh result intentionally - // have different values for "test_string" so we can observe that the - // refresh took effect but the configuration change wasn't considered. - m := testModuleInline(t, map[string]string{ - "main.tf": ` - resource "test_object" "a" { - arg = "after" - } - - output "out" { - value = test_object.a.arg - } - `, - }) - state := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{"arg":"before"}`), - Status: states.ObjectReady, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`)) - }) - - p := simpleMockProvider() - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - Provider: providers.Schema{Block: simpleTestSchema()}, - ResourceTypes: map[string]providers.Schema{ - "test_object": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "arg": {Type: cty.String, Optional: true}, - }, - }, - }, - }, - } - p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse { - newVal, err := cty.Transform(req.PriorState, func(path cty.Path, v cty.Value) (cty.Value, error) { - if len(path) == 1 && path[0] == (cty.GetAttrStep{Name: "arg"}) { - return cty.StringVal("current"), nil - } - return v, nil - }) - if err != nil { - // shouldn't get here - t.Fatalf("ReadResourceFn transform failed") - return providers.ReadResourceResponse{} - } - return providers.ReadResourceResponse{ - NewState: newVal, - } - } - p.UpgradeResourceStateFn = func(req providers.UpgradeResourceStateRequest) (resp providers.UpgradeResourceStateResponse) { - // We should've been given the prior state JSON as our input to upgrade. - if !bytes.Contains(req.RawStateJSON, []byte("before")) { - t.Fatalf("UpgradeResourceState request doesn't contain the 'before' object\n%s", req.RawStateJSON) - } - - // We'll put something different in "arg" as part of upgrading, just - // so that we can verify below that PrevRunState contains the upgraded - // (but NOT refreshed) version of the object. - resp.UpgradedState = cty.ObjectVal(map[string]cty.Value{ - "arg": cty.StringVal("upgraded"), - }) - return resp - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.RefreshOnlyMode, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors\n%s", diags.Err().Error()) - } - - if !p.UpgradeResourceStateCalled { - t.Errorf("Provider's UpgradeResourceState wasn't called; should've been") - } - if !p.ReadResourceCalled { - t.Errorf("Provider's ReadResource wasn't called; should've been") - } - - if got, want := len(plan.Changes.Resources), 0; got != want { - t.Errorf("plan contains resource changes; want none\n%s", spew.Sdump(plan.Changes.Resources)) - } - - if instState := plan.PriorState.ResourceInstance(addr); instState == nil { - t.Errorf("%s has no prior state at all after plan", addr) - } else { - if instState.Current == nil { - t.Errorf("%s has no current object after plan", addr) - } else if got, want := instState.Current.AttrsJSON, `"current"`; !bytes.Contains(got, []byte(want)) { - // Should've saved the result of refreshing - t.Errorf("%s has wrong prior state after plan\ngot:\n%s\n\nwant substring: %s", addr, got, want) - } - } - if instState := plan.PrevRunState.ResourceInstance(addr); instState == nil { - t.Errorf("%s has no previous run state at all after plan", addr) - } else { - if instState.Current == nil { - t.Errorf("%s has no current object in the previous run state", addr) - } else if got, want := instState.Current.AttrsJSON, `"upgraded"`; !bytes.Contains(got, []byte(want)) { - // Should've saved the result of upgrading - t.Errorf("%s has wrong previous run state after plan\ngot:\n%s\n\nwant substring: %s", addr, got, want) - } - } - - // The output value should also have updated. If not, it's likely that we - // skipped updating the working state to match the refreshed state when we - // were evaluating the resource. - if outChangeSrc := plan.Changes.OutputValue(addrs.RootModuleInstance.OutputValue("out")); outChangeSrc == nil { - t.Errorf("no change planned for output value 'out'") - } else { - outChange, err := outChangeSrc.Decode() - if err != nil { - t.Fatalf("failed to decode output value 'out': %s", err) - } - got := outChange.After - want := cty.StringVal("current") - if !want.RawEquals(got) { - t.Errorf("wrong value for output value 'out'\ngot: %#v\nwant: %#v", got, want) - } - } -} - -func TestContext2Plan_refreshOnlyMode_deposed(t *testing.T) { - addr := mustResourceInstanceAddr("test_object.a") - deposedKey := states.DeposedKey("byebye") - - // The configuration, the prior state, and the refresh result intentionally - // have different values for "test_string" so we can observe that the - // refresh took effect but the configuration change wasn't considered. - m := testModuleInline(t, map[string]string{ - "main.tf": ` - resource "test_object" "a" { - arg = "after" - } - - output "out" { - value = test_object.a.arg - } - `, - }) - state := states.BuildState(func(s *states.SyncState) { - // Note that we're intentionally recording a _deposed_ object here, - // and not including a current object, so a normal (non-refresh) - // plan would normally plan to create a new object _and_ destroy - // the deposed one, but refresh-only mode should prevent that. - s.SetResourceInstanceDeposed(addr, deposedKey, &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{"arg":"before"}`), - Status: states.ObjectReady, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`)) - }) - - p := simpleMockProvider() - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - Provider: providers.Schema{Block: simpleTestSchema()}, - ResourceTypes: map[string]providers.Schema{ - "test_object": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "arg": {Type: cty.String, Optional: true}, - }, - }, - }, - }, - } - p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse { - newVal, err := cty.Transform(req.PriorState, func(path cty.Path, v cty.Value) (cty.Value, error) { - if len(path) == 1 && path[0] == (cty.GetAttrStep{Name: "arg"}) { - return cty.StringVal("current"), nil - } - return v, nil - }) - if err != nil { - // shouldn't get here - t.Fatalf("ReadResourceFn transform failed") - return providers.ReadResourceResponse{} - } - return providers.ReadResourceResponse{ - NewState: newVal, - } - } - p.UpgradeResourceStateFn = func(req providers.UpgradeResourceStateRequest) (resp providers.UpgradeResourceStateResponse) { - // We should've been given the prior state JSON as our input to upgrade. - if !bytes.Contains(req.RawStateJSON, []byte("before")) { - t.Fatalf("UpgradeResourceState request doesn't contain the 'before' object\n%s", req.RawStateJSON) - } - - // We'll put something different in "arg" as part of upgrading, just - // so that we can verify below that PrevRunState contains the upgraded - // (but NOT refreshed) version of the object. - resp.UpgradedState = cty.ObjectVal(map[string]cty.Value{ - "arg": cty.StringVal("upgraded"), - }) - return resp - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.RefreshOnlyMode, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors\n%s", diags.Err().Error()) - } - - if !p.UpgradeResourceStateCalled { - t.Errorf("Provider's UpgradeResourceState wasn't called; should've been") - } - if !p.ReadResourceCalled { - t.Errorf("Provider's ReadResource wasn't called; should've been") - } - - if got, want := len(plan.Changes.Resources), 0; got != want { - t.Errorf("plan contains resource changes; want none\n%s", spew.Sdump(plan.Changes.Resources)) - } - - if instState := plan.PriorState.ResourceInstance(addr); instState == nil { - t.Errorf("%s has no prior state at all after plan", addr) - } else { - if obj := instState.Deposed[deposedKey]; obj == nil { - t.Errorf("%s has no deposed object after plan", addr) - } else if got, want := obj.AttrsJSON, `"current"`; !bytes.Contains(got, []byte(want)) { - // Should've saved the result of refreshing - t.Errorf("%s has wrong prior state after plan\ngot:\n%s\n\nwant substring: %s", addr, got, want) - } - } - if instState := plan.PrevRunState.ResourceInstance(addr); instState == nil { - t.Errorf("%s has no previous run state at all after plan", addr) - } else { - if obj := instState.Deposed[deposedKey]; obj == nil { - t.Errorf("%s has no deposed object in the previous run state", addr) - } else if got, want := obj.AttrsJSON, `"upgraded"`; !bytes.Contains(got, []byte(want)) { - // Should've saved the result of upgrading - t.Errorf("%s has wrong previous run state after plan\ngot:\n%s\n\nwant substring: %s", addr, got, want) - } - } - - // The output value should also have updated. If not, it's likely that we - // skipped updating the working state to match the refreshed state when we - // were evaluating the resource. - if outChangeSrc := plan.Changes.OutputValue(addrs.RootModuleInstance.OutputValue("out")); outChangeSrc == nil { - t.Errorf("no change planned for output value 'out'") - } else { - outChange, err := outChangeSrc.Decode() - if err != nil { - t.Fatalf("failed to decode output value 'out': %s", err) - } - got := outChange.After - want := cty.UnknownVal(cty.String) - if !want.RawEquals(got) { - t.Errorf("wrong value for output value 'out'\ngot: %#v\nwant: %#v", got, want) - } - } - - // Deposed objects should not be represented in drift. - if len(plan.DriftedResources) > 0 { - t.Errorf("unexpected drifted resources (%d)", len(plan.DriftedResources)) - } -} - -func TestContext2Plan_refreshOnlyMode_orphan(t *testing.T) { - addr := mustAbsResourceAddr("test_object.a") - - // The configuration, the prior state, and the refresh result intentionally - // have different values for "test_string" so we can observe that the - // refresh took effect but the configuration change wasn't considered. - m := testModuleInline(t, map[string]string{ - "main.tf": ` - resource "test_object" "a" { - arg = "after" - count = 1 - } - - output "out" { - value = test_object.a.*.arg - } - `, - }) - state := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent(addr.Instance(addrs.IntKey(0)), &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{"arg":"before"}`), - Status: states.ObjectReady, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`)) - s.SetResourceInstanceCurrent(addr.Instance(addrs.IntKey(1)), &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{"arg":"before"}`), - Status: states.ObjectReady, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`)) - }) - - p := simpleMockProvider() - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - Provider: providers.Schema{Block: simpleTestSchema()}, - ResourceTypes: map[string]providers.Schema{ - "test_object": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "arg": {Type: cty.String, Optional: true}, - }, - }, - }, - }, - } - p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse { - newVal, err := cty.Transform(req.PriorState, func(path cty.Path, v cty.Value) (cty.Value, error) { - if len(path) == 1 && path[0] == (cty.GetAttrStep{Name: "arg"}) { - return cty.StringVal("current"), nil - } - return v, nil - }) - if err != nil { - // shouldn't get here - t.Fatalf("ReadResourceFn transform failed") - return providers.ReadResourceResponse{} - } - return providers.ReadResourceResponse{ - NewState: newVal, - } - } - p.UpgradeResourceStateFn = func(req providers.UpgradeResourceStateRequest) (resp providers.UpgradeResourceStateResponse) { - // We should've been given the prior state JSON as our input to upgrade. - if !bytes.Contains(req.RawStateJSON, []byte("before")) { - t.Fatalf("UpgradeResourceState request doesn't contain the 'before' object\n%s", req.RawStateJSON) - } - - // We'll put something different in "arg" as part of upgrading, just - // so that we can verify below that PrevRunState contains the upgraded - // (but NOT refreshed) version of the object. - resp.UpgradedState = cty.ObjectVal(map[string]cty.Value{ - "arg": cty.StringVal("upgraded"), - }) - return resp - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.RefreshOnlyMode, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors\n%s", diags.Err().Error()) - } - - if !p.UpgradeResourceStateCalled { - t.Errorf("Provider's UpgradeResourceState wasn't called; should've been") - } - if !p.ReadResourceCalled { - t.Errorf("Provider's ReadResource wasn't called; should've been") - } - - if got, want := len(plan.Changes.Resources), 0; got != want { - t.Errorf("plan contains resource changes; want none\n%s", spew.Sdump(plan.Changes.Resources)) - } - - if rState := plan.PriorState.Resource(addr); rState == nil { - t.Errorf("%s has no prior state at all after plan", addr) - } else { - for i := 0; i < 2; i++ { - instKey := addrs.IntKey(i) - if obj := rState.Instance(instKey).Current; obj == nil { - t.Errorf("%s%s has no object after plan", addr, instKey) - } else if got, want := obj.AttrsJSON, `"current"`; !bytes.Contains(got, []byte(want)) { - // Should've saved the result of refreshing - t.Errorf("%s%s has wrong prior state after plan\ngot:\n%s\n\nwant substring: %s", addr, instKey, got, want) - } - } - } - if rState := plan.PrevRunState.Resource(addr); rState == nil { - t.Errorf("%s has no prior state at all after plan", addr) - } else { - for i := 0; i < 2; i++ { - instKey := addrs.IntKey(i) - if obj := rState.Instance(instKey).Current; obj == nil { - t.Errorf("%s%s has no object after plan", addr, instKey) - } else if got, want := obj.AttrsJSON, `"upgraded"`; !bytes.Contains(got, []byte(want)) { - // Should've saved the result of upgrading - t.Errorf("%s%s has wrong prior state after plan\ngot:\n%s\n\nwant substring: %s", addr, instKey, got, want) - } - } - } - - // The output value should also have updated. If not, it's likely that we - // skipped updating the working state to match the refreshed state when we - // were evaluating the resource. - if outChangeSrc := plan.Changes.OutputValue(addrs.RootModuleInstance.OutputValue("out")); outChangeSrc == nil { - t.Errorf("no change planned for output value 'out'") - } else { - outChange, err := outChangeSrc.Decode() - if err != nil { - t.Fatalf("failed to decode output value 'out': %s", err) - } - got := outChange.After - want := cty.TupleVal([]cty.Value{cty.StringVal("current"), cty.StringVal("current")}) - if !want.RawEquals(got) { - t.Errorf("wrong value for output value 'out'\ngot: %#v\nwant: %#v", got, want) - } - } -} - -func TestContext2Plan_invalidSensitiveModuleOutput(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "child/main.tf": ` -output "out" { - value = sensitive("xyz") -}`, - "main.tf": ` -module "child" { - source = "./child" -} - -output "root" { - value = module.child.out -}`, - }) - - ctx := testContext2(t, &ContextOpts{}) - - _, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if !diags.HasErrors() { - t.Fatal("succeeded; want errors") - } - if got, want := diags.Err().Error(), "Output refers to sensitive values"; !strings.Contains(got, want) { - t.Fatalf("wrong error:\ngot: %s\nwant: message containing %q", got, want) - } -} - -func TestContext2Plan_planDataSourceSensitiveNested(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "test_instance" "bar" { -} - -data "test_data_source" "foo" { - foo { - bar = test_instance.bar.sensitive - } -} -`, - }) - - p := new(MockProvider) - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { - resp.PlannedState = cty.ObjectVal(map[string]cty.Value{ - "sensitive": cty.UnknownVal(cty.String), - }) - return resp - } - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test_instance": { - Attributes: map[string]*configschema.Attribute{ - "sensitive": { - Type: cty.String, - Computed: true, - Sensitive: true, - }, - }, - }, - }, - DataSources: map[string]*configschema.Block{ - "test_data_source": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - }, - BlockTypes: map[string]*configschema.NestedBlock{ - "foo": { - Block: configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "bar": {Type: cty.String, Optional: true}, - }, - }, - Nesting: configschema.NestingSet, - }, - }, - }, - }, - }) - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("data.test_data_source.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"string":"data_id", "foo":[{"bar":"old"}]}`), - AttrSensitivePaths: []cty.PathValueMarks{ - { - Path: cty.GetAttrPath("foo"), - Marks: cty.NewValueMarks(marks.Sensitive), - }, - }, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_instance.bar").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"sensitive":"old"}`), - AttrSensitivePaths: []cty.PathValueMarks{ - { - Path: cty.GetAttrPath("sensitive"), - Marks: cty.NewValueMarks(marks.Sensitive), - }, - }, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - for _, res := range plan.Changes.Resources { - switch res.Addr.String() { - case "test_instance.bar": - if res.Action != plans.Update { - t.Fatalf("unexpected %s change for %s", res.Action, res.Addr) - } - case "data.test_data_source.foo": - if res.Action != plans.Read { - t.Fatalf("unexpected %s change for %s", res.Action, res.Addr) - } - default: - t.Fatalf("unexpected %s change for %s", res.Action, res.Addr) - } - } -} - -func TestContext2Plan_forceReplace(t *testing.T) { - addrA := mustResourceInstanceAddr("test_object.a") - addrB := mustResourceInstanceAddr("test_object.b") - m := testModuleInline(t, map[string]string{ - "main.tf": ` - resource "test_object" "a" { - } - resource "test_object" "b" { - } - `, - }) - - state := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent(addrA, &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{}`), - Status: states.ObjectReady, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`)) - s.SetResourceInstanceCurrent(addrB, &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{}`), - Status: states.ObjectReady, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`)) - }) - - p := simpleMockProvider() - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.NormalMode, - ForceReplace: []addrs.AbsResourceInstance{ - addrA, - }, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors\n%s", diags.Err().Error()) - } - - t.Run(addrA.String(), func(t *testing.T) { - instPlan := plan.Changes.ResourceInstance(addrA) - if instPlan == nil { - t.Fatalf("no plan for %s at all", addrA) - } - - if got, want := instPlan.Action, plans.DeleteThenCreate; got != want { - t.Errorf("wrong planned action\ngot: %s\nwant: %s", got, want) - } - if got, want := instPlan.ActionReason, plans.ResourceInstanceReplaceByRequest; got != want { - t.Errorf("wrong action reason\ngot: %s\nwant: %s", got, want) - } - }) - t.Run(addrB.String(), func(t *testing.T) { - instPlan := plan.Changes.ResourceInstance(addrB) - if instPlan == nil { - t.Fatalf("no plan for %s at all", addrB) - } - - if got, want := instPlan.Action, plans.NoOp; got != want { - t.Errorf("wrong planned action\ngot: %s\nwant: %s", got, want) - } - if got, want := instPlan.ActionReason, plans.ResourceInstanceChangeNoReason; got != want { - t.Errorf("wrong action reason\ngot: %s\nwant: %s", got, want) - } - }) -} - -func TestContext2Plan_forceReplaceIncompleteAddr(t *testing.T) { - addr0 := mustResourceInstanceAddr("test_object.a[0]") - addr1 := mustResourceInstanceAddr("test_object.a[1]") - addrBare := mustResourceInstanceAddr("test_object.a") - m := testModuleInline(t, map[string]string{ - "main.tf": ` - resource "test_object" "a" { - count = 2 - } - `, - }) - - state := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent(addr0, &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{}`), - Status: states.ObjectReady, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`)) - s.SetResourceInstanceCurrent(addr1, &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{}`), - Status: states.ObjectReady, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`)) - }) - - p := simpleMockProvider() - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.NormalMode, - ForceReplace: []addrs.AbsResourceInstance{ - addrBare, - }, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors\n%s", diags.Err().Error()) - } - diagsErr := diags.ErrWithWarnings() - if diagsErr == nil { - t.Fatalf("no warnings were returned") - } - if got, want := diagsErr.Error(), "Incompletely-matched force-replace resource instance"; !strings.Contains(got, want) { - t.Errorf("missing expected warning\ngot:\n%s\n\nwant substring: %s", got, want) - } - - t.Run(addr0.String(), func(t *testing.T) { - instPlan := plan.Changes.ResourceInstance(addr0) - if instPlan == nil { - t.Fatalf("no plan for %s at all", addr0) - } - - if got, want := instPlan.Action, plans.NoOp; got != want { - t.Errorf("wrong planned action\ngot: %s\nwant: %s", got, want) - } - if got, want := instPlan.ActionReason, plans.ResourceInstanceChangeNoReason; got != want { - t.Errorf("wrong action reason\ngot: %s\nwant: %s", got, want) - } - }) - t.Run(addr1.String(), func(t *testing.T) { - instPlan := plan.Changes.ResourceInstance(addr1) - if instPlan == nil { - t.Fatalf("no plan for %s at all", addr1) - } - - if got, want := instPlan.Action, plans.NoOp; got != want { - t.Errorf("wrong planned action\ngot: %s\nwant: %s", got, want) - } - if got, want := instPlan.ActionReason, plans.ResourceInstanceChangeNoReason; got != want { - t.Errorf("wrong action reason\ngot: %s\nwant: %s", got, want) - } - }) -} - -// Verify that adding a module instance does force existing module data sources -// to be deferred -func TestContext2Plan_noChangeDataSourceAddingModuleInstance(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -locals { - data = { - a = "a" - b = "b" - } -} - -module "one" { - source = "./mod" - for_each = local.data - input = each.value -} - -module "two" { - source = "./mod" - for_each = module.one - input = each.value.output -} -`, - "mod/main.tf": ` -variable "input" { -} - -resource "test_resource" "x" { - value = var.input -} - -data "test_data_source" "d" { - foo = test_resource.x.id -} - -output "output" { - value = test_resource.x.id -} -`, - }) - - p := testProvider("test") - p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{ - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("data"), - "foo": cty.StringVal("foo"), - }), - } - state := states.NewState() - modOne := addrs.RootModuleInstance.Child("one", addrs.StringKey("a")) - modTwo := addrs.RootModuleInstance.Child("two", addrs.StringKey("a")) - one := state.EnsureModule(modOne) - two := state.EnsureModule(modTwo) - one.SetResourceInstanceCurrent( - mustResourceInstanceAddr(`test_resource.x`).Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo","value":"a"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - one.SetResourceInstanceCurrent( - mustResourceInstanceAddr(`data.test_data_source.d`).Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"data"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - two.SetResourceInstanceCurrent( - mustResourceInstanceAddr(`test_resource.x`).Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo","value":"foo"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - two.SetResourceInstanceCurrent( - mustResourceInstanceAddr(`data.test_data_source.d`).Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"data"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - for _, res := range plan.Changes.Resources { - // both existing data sources should be read during plan - if res.Addr.Module[0].InstanceKey == addrs.StringKey("b") { - continue - } - - if res.Addr.Resource.Resource.Mode == addrs.DataResourceMode && res.Action != plans.NoOp { - t.Errorf("unexpected %s plan for %s", res.Action, res.Addr) - } - } -} - -func TestContext2Plan_moduleExpandOrphansResourceInstance(t *testing.T) { - // This test deals with the situation where a user has changed the - // repetition/expansion mode for a module call while there are already - // resource instances from the previous declaration in the state. - // - // This is conceptually just the same as removing the resources - // from the module configuration only for that instance, but the - // implementation of it ends up a little different because it's - // an entry in the resource address's _module path_ that we'll find - // missing, rather than the resource's own instance key, and so - // our analyses need to handle that situation by indicating that all - // of the resources under the missing module instance have zero - // instances, regardless of which resource in that module we might - // be asking about, and do so without tripping over any missing - // registrations in the instance expander that might lead to panics - // if we aren't careful. - // - // (For some history here, see https://github.com/hashicorp/terraform/issues/30110 ) - - addrNoKey := mustResourceInstanceAddr("module.child.test_object.a[0]") - addrZeroKey := mustResourceInstanceAddr("module.child[0].test_object.a[0]") - m := testModuleInline(t, map[string]string{ - "main.tf": ` - module "child" { - source = "./child" - count = 1 - } - `, - "child/main.tf": ` - resource "test_object" "a" { - count = 1 - } - `, - }) - - state := states.BuildState(func(s *states.SyncState) { - // Notice that addrNoKey is the address which lacks any instance key - // for module.child, and so that module instance doesn't match the - // call declared above with count = 1, and therefore the resource - // inside is "orphaned" even though the resource block actually - // still exists there. - s.SetResourceInstanceCurrent(addrNoKey, &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{}`), - Status: states.ObjectReady, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`)) - }) - - p := simpleMockProvider() - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.NormalMode, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors\n%s", diags.Err().Error()) - } - - t.Run(addrNoKey.String(), func(t *testing.T) { - instPlan := plan.Changes.ResourceInstance(addrNoKey) - if instPlan == nil { - t.Fatalf("no plan for %s at all", addrNoKey) - } - - if got, want := instPlan.Addr, addrNoKey; !got.Equal(want) { - t.Errorf("wrong current address\ngot: %s\nwant: %s", got, want) - } - if got, want := instPlan.PrevRunAddr, addrNoKey; !got.Equal(want) { - t.Errorf("wrong previous run address\ngot: %s\nwant: %s", got, want) - } - if got, want := instPlan.Action, plans.Delete; got != want { - t.Errorf("wrong planned action\ngot: %s\nwant: %s", got, want) - } - if got, want := instPlan.ActionReason, plans.ResourceInstanceDeleteBecauseNoModule; got != want { - t.Errorf("wrong action reason\ngot: %s\nwant: %s", got, want) - } - }) - - t.Run(addrZeroKey.String(), func(t *testing.T) { - instPlan := plan.Changes.ResourceInstance(addrZeroKey) - if instPlan == nil { - t.Fatalf("no plan for %s at all", addrZeroKey) - } - - if got, want := instPlan.Addr, addrZeroKey; !got.Equal(want) { - t.Errorf("wrong current address\ngot: %s\nwant: %s", got, want) - } - if got, want := instPlan.PrevRunAddr, addrZeroKey; !got.Equal(want) { - t.Errorf("wrong previous run address\ngot: %s\nwant: %s", got, want) - } - if got, want := instPlan.Action, plans.Create; got != want { - t.Errorf("wrong planned action\ngot: %s\nwant: %s", got, want) - } - if got, want := instPlan.ActionReason, plans.ResourceInstanceChangeNoReason; got != want { - t.Errorf("wrong action reason\ngot: %s\nwant: %s", got, want) - } - }) -} - -func TestContext2Plan_resourcePreconditionPostcondition(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -variable "boop" { - type = string -} - -resource "test_resource" "a" { - value = var.boop - lifecycle { - precondition { - condition = var.boop == "boop" - error_message = "Wrong boop." - } - postcondition { - condition = self.output != "" - error_message = "Output must not be blank." - } - } -} - -`, - }) - - p := testProvider("test") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test_resource": { - Attributes: map[string]*configschema.Attribute{ - "value": { - Type: cty.String, - Required: true, - }, - "output": { - Type: cty.String, - Computed: true, - }, - }, - }, - }, - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - t.Run("conditions pass", func(t *testing.T) { - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { - m := req.ProposedNewState.AsValueMap() - m["output"] = cty.StringVal("bar") - - resp.PlannedState = cty.ObjectVal(m) - resp.LegacyTypeSystem = true - return resp - } - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "boop": &InputValue{ - Value: cty.StringVal("boop"), - SourceType: ValueFromCLIArg, - }, - }, - }) - assertNoErrors(t, diags) - for _, res := range plan.Changes.Resources { - switch res.Addr.String() { - case "test_resource.a": - if res.Action != plans.Create { - t.Fatalf("unexpected %s change for %s", res.Action, res.Addr) - } - default: - t.Fatalf("unexpected %s change for %s", res.Action, res.Addr) - } - } - }) - - t.Run("precondition fail", func(t *testing.T) { - _, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "boop": &InputValue{ - Value: cty.StringVal("nope"), - SourceType: ValueFromCLIArg, - }, - }, - }) - if !diags.HasErrors() { - t.Fatal("succeeded; want errors") - } - if got, want := diags.Err().Error(), "Resource precondition failed: Wrong boop."; got != want { - t.Fatalf("wrong error:\ngot: %s\nwant: %q", got, want) - } - if p.PlanResourceChangeCalled { - t.Errorf("Provider's PlanResourceChange was called; should'nt've been") - } - }) - - t.Run("precondition fail refresh-only", func(t *testing.T) { - state := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent(mustResourceInstanceAddr("test_resource.a"), &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{"value":"boop","output":"blorp"}`), - Status: states.ObjectReady, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`)) - }) - _, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.RefreshOnlyMode, - SetVariables: InputValues{ - "boop": &InputValue{ - Value: cty.StringVal("nope"), - SourceType: ValueFromCLIArg, - }, - }, - }) - assertNoErrors(t, diags) - if len(diags) == 0 { - t.Fatalf("no diags, but should have warnings") - } - if got, want := diags.ErrWithWarnings().Error(), "Resource precondition failed: Wrong boop."; got != want { - t.Fatalf("wrong warning:\ngot: %s\nwant: %q", got, want) - } - if !p.ReadResourceCalled { - t.Errorf("Provider's ReadResource wasn't called; should've been") - } - }) - - t.Run("postcondition fail", func(t *testing.T) { - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { - m := req.ProposedNewState.AsValueMap() - m["output"] = cty.StringVal("") - - resp.PlannedState = cty.ObjectVal(m) - resp.LegacyTypeSystem = true - return resp - } - _, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "boop": &InputValue{ - Value: cty.StringVal("boop"), - SourceType: ValueFromCLIArg, - }, - }, - }) - if !diags.HasErrors() { - t.Fatal("succeeded; want errors") - } - if got, want := diags.Err().Error(), "Resource postcondition failed: Output must not be blank."; got != want { - t.Fatalf("wrong error:\ngot: %s\nwant: %q", got, want) - } - if !p.PlanResourceChangeCalled { - t.Errorf("Provider's PlanResourceChange wasn't called; should've been") - } - }) - - t.Run("postcondition fail refresh-only", func(t *testing.T) { - state := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent(mustResourceInstanceAddr("test_resource.a"), &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{"value":"boop","output":"blorp"}`), - Status: states.ObjectReady, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`)) - }) - p.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) { - newVal, err := cty.Transform(req.PriorState, func(path cty.Path, v cty.Value) (cty.Value, error) { - if len(path) == 1 && path[0] == (cty.GetAttrStep{Name: "output"}) { - return cty.StringVal(""), nil - } - return v, nil - }) - if err != nil { - // shouldn't get here - t.Fatalf("ReadResourceFn transform failed") - return providers.ReadResourceResponse{} - } - return providers.ReadResourceResponse{ - NewState: newVal, - } - } - _, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.RefreshOnlyMode, - SetVariables: InputValues{ - "boop": &InputValue{ - Value: cty.StringVal("boop"), - SourceType: ValueFromCLIArg, - }, - }, - }) - assertNoErrors(t, diags) - if len(diags) == 0 { - t.Fatalf("no diags, but should have warnings") - } - if got, want := diags.ErrWithWarnings().Error(), "Resource postcondition failed: Output must not be blank."; got != want { - t.Fatalf("wrong warning:\ngot: %s\nwant: %q", got, want) - } - if !p.ReadResourceCalled { - t.Errorf("Provider's ReadResource wasn't called; should've been") - } - if p.PlanResourceChangeCalled { - t.Errorf("Provider's PlanResourceChange was called; should'nt've been") - } - }) - - t.Run("precondition and postcondition fail refresh-only", func(t *testing.T) { - state := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent(mustResourceInstanceAddr("test_resource.a"), &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{"value":"boop","output":"blorp"}`), - Status: states.ObjectReady, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`)) - }) - p.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) { - newVal, err := cty.Transform(req.PriorState, func(path cty.Path, v cty.Value) (cty.Value, error) { - if len(path) == 1 && path[0] == (cty.GetAttrStep{Name: "output"}) { - return cty.StringVal(""), nil - } - return v, nil - }) - if err != nil { - // shouldn't get here - t.Fatalf("ReadResourceFn transform failed") - return providers.ReadResourceResponse{} - } - return providers.ReadResourceResponse{ - NewState: newVal, - } - } - _, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.RefreshOnlyMode, - SetVariables: InputValues{ - "boop": &InputValue{ - Value: cty.StringVal("nope"), - SourceType: ValueFromCLIArg, - }, - }, - }) - assertNoErrors(t, diags) - if got, want := len(diags), 2; got != want { - t.Errorf("wrong number of warnings, got %d, want %d", got, want) - } - warnings := diags.ErrWithWarnings().Error() - wantWarnings := []string{ - "Resource precondition failed: Wrong boop.", - "Resource postcondition failed: Output must not be blank.", - } - for _, want := range wantWarnings { - if !strings.Contains(warnings, want) { - t.Errorf("missing warning:\ngot: %s\nwant to contain: %q", warnings, want) - } - } - if !p.ReadResourceCalled { - t.Errorf("Provider's ReadResource wasn't called; should've been") - } - if p.PlanResourceChangeCalled { - t.Errorf("Provider's PlanResourceChange was called; should'nt've been") - } - }) -} - -func TestContext2Plan_dataSourcePreconditionPostcondition(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -variable "boop" { - type = string -} - -data "test_data_source" "a" { - foo = var.boop - lifecycle { - precondition { - condition = var.boop == "boop" - error_message = "Wrong boop." - } - postcondition { - condition = length(self.results) > 0 - error_message = "Results cannot be empty." - } - } -} - -resource "test_resource" "a" { - value = data.test_data_source.a.results[0] -} -`, - }) - - p := testProvider("test") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test_resource": { - Attributes: map[string]*configschema.Attribute{ - "value": { - Type: cty.String, - Required: true, - }, - }, - }, - }, - DataSources: map[string]*configschema.Block{ - "test_data_source": { - Attributes: map[string]*configschema.Attribute{ - "foo": { - Type: cty.String, - Required: true, - }, - "results": { - Type: cty.List(cty.String), - Computed: true, - }, - }, - }, - }, - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - t.Run("conditions pass", func(t *testing.T) { - p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{ - State: cty.ObjectVal(map[string]cty.Value{ - "foo": cty.StringVal("boop"), - "results": cty.ListVal([]cty.Value{cty.StringVal("boop")}), - }), - } - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "boop": &InputValue{ - Value: cty.StringVal("boop"), - SourceType: ValueFromCLIArg, - }, - }, - }) - assertNoErrors(t, diags) - for _, res := range plan.Changes.Resources { - switch res.Addr.String() { - case "test_resource.a": - if res.Action != plans.Create { - t.Fatalf("unexpected %s change for %s", res.Action, res.Addr) - } - case "data.test_data_source.a": - if res.Action != plans.Read { - t.Fatalf("unexpected %s change for %s", res.Action, res.Addr) - } - default: - t.Fatalf("unexpected %s change for %s", res.Action, res.Addr) - } - } - - addr := mustResourceInstanceAddr("data.test_data_source.a") - if gotResult := plan.Checks.GetObjectResult(addr); gotResult == nil { - t.Errorf("no check result for %s", addr) - } else { - wantResult := &states.CheckResultObject{ - Status: checks.StatusPass, - } - if diff := cmp.Diff(wantResult, gotResult, valueComparer); diff != "" { - t.Errorf("wrong check result for %s\n%s", addr, diff) - } - } - }) - - t.Run("precondition fail", func(t *testing.T) { - _, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "boop": &InputValue{ - Value: cty.StringVal("nope"), - SourceType: ValueFromCLIArg, - }, - }, - }) - if !diags.HasErrors() { - t.Fatal("succeeded; want errors") - } - if got, want := diags.Err().Error(), "Resource precondition failed: Wrong boop."; got != want { - t.Fatalf("wrong error:\ngot: %s\nwant: %q", got, want) - } - if p.ReadDataSourceCalled { - t.Errorf("Provider's ReadResource was called; should'nt've been") - } - }) - - t.Run("precondition fail refresh-only", func(t *testing.T) { - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.RefreshOnlyMode, - SetVariables: InputValues{ - "boop": &InputValue{ - Value: cty.StringVal("nope"), - SourceType: ValueFromCLIArg, - }, - }, - }) - assertNoErrors(t, diags) - if len(diags) == 0 { - t.Fatalf("no diags, but should have warnings") - } - if got, want := diags.ErrWithWarnings().Error(), "Resource precondition failed: Wrong boop."; got != want { - t.Fatalf("wrong warning:\ngot: %s\nwant: %q", got, want) - } - for _, res := range plan.Changes.Resources { - switch res.Addr.String() { - case "test_resource.a": - if res.Action != plans.Create { - t.Fatalf("unexpected %s change for %s", res.Action, res.Addr) - } - case "data.test_data_source.a": - if res.Action != plans.Read { - t.Fatalf("unexpected %s change for %s", res.Action, res.Addr) - } - default: - t.Fatalf("unexpected %s change for %s", res.Action, res.Addr) - } - } - }) - - t.Run("postcondition fail", func(t *testing.T) { - p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{ - State: cty.ObjectVal(map[string]cty.Value{ - "foo": cty.StringVal("boop"), - "results": cty.ListValEmpty(cty.String), - }), - } - _, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "boop": &InputValue{ - Value: cty.StringVal("boop"), - SourceType: ValueFromCLIArg, - }, - }, - }) - if !diags.HasErrors() { - t.Fatal("succeeded; want errors") - } - if got, want := diags.Err().Error(), "Resource postcondition failed: Results cannot be empty."; got != want { - t.Fatalf("wrong error:\ngot: %s\nwant: %q", got, want) - } - if !p.ReadDataSourceCalled { - t.Errorf("Provider's ReadDataSource wasn't called; should've been") - } - }) - - t.Run("postcondition fail refresh-only", func(t *testing.T) { - p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{ - State: cty.ObjectVal(map[string]cty.Value{ - "foo": cty.StringVal("boop"), - "results": cty.ListValEmpty(cty.String), - }), - } - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.RefreshOnlyMode, - SetVariables: InputValues{ - "boop": &InputValue{ - Value: cty.StringVal("boop"), - SourceType: ValueFromCLIArg, - }, - }, - }) - assertNoErrors(t, diags) - if got, want := diags.ErrWithWarnings().Error(), "Resource postcondition failed: Results cannot be empty."; got != want { - t.Fatalf("wrong error:\ngot: %s\nwant: %q", got, want) - } - addr := mustResourceInstanceAddr("data.test_data_source.a") - if gotResult := plan.Checks.GetObjectResult(addr); gotResult == nil { - t.Errorf("no check result for %s", addr) - } else { - wantResult := &states.CheckResultObject{ - Status: checks.StatusFail, - FailureMessages: []string{ - "Results cannot be empty.", - }, - } - if diff := cmp.Diff(wantResult, gotResult, valueComparer); diff != "" { - t.Errorf("wrong check result\n%s", diff) - } - } - }) - - t.Run("precondition and postcondition fail refresh-only", func(t *testing.T) { - p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{ - State: cty.ObjectVal(map[string]cty.Value{ - "foo": cty.StringVal("nope"), - "results": cty.ListValEmpty(cty.String), - }), - } - _, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.RefreshOnlyMode, - SetVariables: InputValues{ - "boop": &InputValue{ - Value: cty.StringVal("nope"), - SourceType: ValueFromCLIArg, - }, - }, - }) - assertNoErrors(t, diags) - if got, want := len(diags), 2; got != want { - t.Errorf("wrong number of warnings, got %d, want %d", got, want) - } - warnings := diags.ErrWithWarnings().Error() - wantWarnings := []string{ - "Resource precondition failed: Wrong boop.", - "Resource postcondition failed: Results cannot be empty.", - } - for _, want := range wantWarnings { - if !strings.Contains(warnings, want) { - t.Errorf("missing warning:\ngot: %s\nwant to contain: %q", warnings, want) - } - } - }) -} - -func TestContext2Plan_outputPrecondition(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -variable "boop" { - type = string -} - -output "a" { - value = var.boop - precondition { - condition = var.boop == "boop" - error_message = "Wrong boop." - } -} -`, - }) - - p := testProvider("test") - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - t.Run("condition pass", func(t *testing.T) { - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "boop": &InputValue{ - Value: cty.StringVal("boop"), - SourceType: ValueFromCLIArg, - }, - }, - }) - assertNoErrors(t, diags) - addr := addrs.RootModuleInstance.OutputValue("a") - outputPlan := plan.Changes.OutputValue(addr) - if outputPlan == nil { - t.Fatalf("no plan for %s at all", addr) - } - if got, want := outputPlan.Addr, addr; !got.Equal(want) { - t.Errorf("wrong current address\ngot: %s\nwant: %s", got, want) - } - if got, want := outputPlan.Action, plans.Create; got != want { - t.Errorf("wrong planned action\ngot: %s\nwant: %s", got, want) - } - if gotResult := plan.Checks.GetObjectResult(addr); gotResult == nil { - t.Errorf("no check result for %s", addr) - } else { - wantResult := &states.CheckResultObject{ - Status: checks.StatusPass, - } - if diff := cmp.Diff(wantResult, gotResult, valueComparer); diff != "" { - t.Errorf("wrong check result\n%s", diff) - } - } - }) - - t.Run("condition fail", func(t *testing.T) { - _, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "boop": &InputValue{ - Value: cty.StringVal("nope"), - SourceType: ValueFromCLIArg, - }, - }, - }) - if !diags.HasErrors() { - t.Fatal("succeeded; want errors") - } - if got, want := diags.Err().Error(), "Module output value precondition failed: Wrong boop."; got != want { - t.Fatalf("wrong error:\ngot: %s\nwant: %q", got, want) - } - }) - - t.Run("condition fail refresh-only", func(t *testing.T) { - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.RefreshOnlyMode, - SetVariables: InputValues{ - "boop": &InputValue{ - Value: cty.StringVal("nope"), - SourceType: ValueFromCLIArg, - }, - }, - }) - assertNoErrors(t, diags) - if len(diags) == 0 { - t.Fatalf("no diags, but should have warnings") - } - if got, want := diags.ErrWithWarnings().Error(), "Module output value precondition failed: Wrong boop."; got != want { - t.Errorf("wrong warning:\ngot: %s\nwant: %q", got, want) - } - addr := addrs.RootModuleInstance.OutputValue("a") - outputPlan := plan.Changes.OutputValue(addr) - if outputPlan == nil { - t.Fatalf("no plan for %s at all", addr) - } - if got, want := outputPlan.Addr, addr; !got.Equal(want) { - t.Errorf("wrong current address\ngot: %s\nwant: %s", got, want) - } - if got, want := outputPlan.Action, plans.Create; got != want { - t.Errorf("wrong planned action\ngot: %s\nwant: %s", got, want) - } - if gotResult := plan.Checks.GetObjectResult(addr); gotResult == nil { - t.Errorf("no condition result for %s", addr) - } else { - wantResult := &states.CheckResultObject{ - Status: checks.StatusFail, - FailureMessages: []string{"Wrong boop."}, - } - if diff := cmp.Diff(wantResult, gotResult, valueComparer); diff != "" { - t.Errorf("wrong condition result\n%s", diff) - } - } - }) -} - -func TestContext2Plan_preconditionErrors(t *testing.T) { - testCases := []struct { - condition string - wantSummary string - wantDetail string - }{ - { - "data.test_data_source", - "Invalid reference", - `The "data" object must be followed by two attribute names`, - }, - { - "self.value", - `Invalid "self" reference`, - "only in resource provisioner, connection, and postcondition blocks", - }, - { - "data.foo.bar", - "Reference to undeclared resource", - `A data resource "foo" "bar" has not been declared in the root module`, - }, - { - "test_resource.b.value", - "Invalid condition result", - "Condition expression must return either true or false", - }, - { - "test_resource.c.value", - "Invalid condition result", - "Invalid condition result value: a bool is required", - }, - } - - p := testProvider("test") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - for _, tc := range testCases { - t.Run(tc.condition, func(t *testing.T) { - main := fmt.Sprintf(` - resource "test_resource" "a" { - value = var.boop - lifecycle { - precondition { - condition = %s - error_message = "Not relevant." - } - } - } - - resource "test_resource" "b" { - value = null - } - - resource "test_resource" "c" { - value = "bar" - } - `, tc.condition) - m := testModuleInline(t, map[string]string{"main.tf": main}) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if !diags.HasErrors() { - t.Fatal("succeeded; want errors") - } - - if !plan.Errored { - t.Fatal("plan failed to record error") - } - - diag := diags[0] - if got, want := diag.Description().Summary, tc.wantSummary; got != want { - t.Errorf("unexpected summary\n got: %s\nwant: %s", got, want) - } - if got, want := diag.Description().Detail, tc.wantDetail; !strings.Contains(got, want) { - t.Errorf("unexpected summary\ngot: %s\nwant to contain %q", got, want) - } - - for _, kv := range plan.Checks.ConfigResults.Elements() { - // All these are configuration or evaluation errors - if kv.Value.Status != checks.StatusError { - t.Errorf("incorrect status, got %s", kv.Value.Status) - } - } - }) - } -} - -func TestContext2Plan_preconditionSensitiveValues(t *testing.T) { - p := testProvider("test") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - m := testModuleInline(t, map[string]string{ - "main.tf": ` -variable "boop" { - sensitive = true - type = string -} - -output "a" { - sensitive = true - value = var.boop - - precondition { - condition = length(var.boop) <= 4 - error_message = "Boop is too long, ${length(var.boop)} > 4" - } -} -`, - }) - - _, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "boop": &InputValue{ - Value: cty.StringVal("bleep"), - SourceType: ValueFromCLIArg, - }, - }, - }) - if !diags.HasErrors() { - t.Fatal("succeeded; want errors") - } - if got, want := len(diags), 2; got != want { - t.Errorf("wrong number of diags, got %d, want %d", got, want) - } - for _, diag := range diags { - desc := diag.Description() - if desc.Summary == "Module output value precondition failed" { - if got, want := desc.Detail, "This check failed, but has an invalid error message as described in the other accompanying messages."; !strings.Contains(got, want) { - t.Errorf("unexpected detail\ngot: %s\nwant to contain %q", got, want) - } - } else if desc.Summary == "Error message refers to sensitive values" { - if got, want := desc.Detail, "The error expression used to explain this condition refers to sensitive values, so Terraform will not display the resulting message."; !strings.Contains(got, want) { - t.Errorf("unexpected detail\ngot: %s\nwant to contain %q", got, want) - } - } else { - t.Errorf("unexpected summary\ngot: %s", desc.Summary) - } - } -} - -func TestContext2Plan_triggeredBy(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "test_object" "a" { - count = 1 - test_string = "new" -} -resource "test_object" "b" { - count = 1 - test_string = test_object.a[count.index].test_string - lifecycle { - # the change to test_string in the other resource should trigger replacement - replace_triggered_by = [ test_object.a[count.index].test_string ] - } -} -`, - }) - - p := simpleMockProvider() - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - state := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.a[0]"), - &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{"test_string":"old"}`), - Status: states.ObjectReady, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - s.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.b[0]"), - &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{}`), - Status: states.ObjectReady, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.NormalMode, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors\n%s", diags.Err().Error()) - } - for _, c := range plan.Changes.Resources { - switch c.Addr.String() { - case "test_object.a[0]": - if c.Action != plans.Update { - t.Fatalf("unexpected %s change for %s\n", c.Action, c.Addr) - } - case "test_object.b[0]": - if c.Action != plans.DeleteThenCreate { - t.Fatalf("unexpected %s change for %s\n", c.Action, c.Addr) - } - if c.ActionReason != plans.ResourceInstanceReplaceByTriggers { - t.Fatalf("incorrect reason for change: %s\n", c.ActionReason) - } - default: - t.Fatal("unexpected change", c.Addr, c.Action) - } - } -} - -func TestContext2Plan_dataSchemaChange(t *testing.T) { - // We can't decode the prior state when a data source upgrades the schema - // in an incompatible way. Since prior state for data sources is purely - // informational, decoding should be skipped altogether. - m := testModuleInline(t, map[string]string{ - "main.tf": ` -data "test_object" "a" { - obj { - # args changes from a list to a map - args = { - val = "string" - } - } -} -`, - }) - - p := new(MockProvider) - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - DataSources: map[string]*configschema.Block{ - "test_object": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - }, - BlockTypes: map[string]*configschema.NestedBlock{ - "obj": { - Block: configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "args": {Type: cty.Map(cty.String), Optional: true}, - }, - }, - Nesting: configschema.NestingSet, - }, - }, - }, - }, - }) - - p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) { - resp.State = req.Config - return resp - } - - state := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent(mustResourceInstanceAddr(`data.test_object.a`), &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{"id":"old","obj":[{"args":["string"]}]}`), - Status: states.ObjectReady, - }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`)) - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - _, diags := ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) -} - -func TestContext2Plan_applyGraphError(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "test_object" "a" { -} -resource "test_object" "b" { - depends_on = [test_object.a] -} -`, - }) - - p := simpleMockProvider() - - // Here we introduce a cycle via state which only shows up in the apply - // graph where the actual destroy instances are connected in the graph. - // This could happen for example when a user has an existing state with - // stored dependencies, and changes the config in such a way that - // contradicts the stored dependencies. - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.a").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectTainted, - AttrsJSON: []byte(`{"test_string":"a"}`), - Dependencies: []addrs.ConfigResource{mustResourceInstanceAddr("test_object.b").ContainingResource().Config()}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.b").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectTainted, - AttrsJSON: []byte(`{"test_string":"b"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - _, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.NormalMode, - }) - if !diags.HasErrors() { - t.Fatal("cycle error not detected") - } - - msg := diags.ErrWithWarnings().Error() - if !strings.Contains(msg, "Cycle") { - t.Fatalf("no cycle error found:\n got: %s\n", msg) - } -} - -// plan a destroy with no state where configuration could fail to evaluate -// expansion indexes. -func TestContext2Plan_emptyDestroy(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -locals { - enable = true - value = local.enable ? module.example[0].out : null -} - -module "example" { - count = local.enable ? 1 : 0 - source = "./example" -} -`, - "example/main.tf": ` -resource "test_resource" "x" { -} - -output "out" { - value = test_resource.x -} -`, - }) - - p := testProvider("test") - state := states.NewState() - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - - assertNoErrors(t, diags) - - // ensure that the given states are valid and can be serialized - if plan.PrevRunState == nil { - t.Fatal("nil plan.PrevRunState") - } - if plan.PriorState == nil { - t.Fatal("nil plan.PriorState") - } -} - -// A deposed instances which no longer exists during ReadResource creates NoOp -// change, which should not effect the plan. -func TestContext2Plan_deposedNoLongerExists(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "test_object" "b" { - count = 1 - test_string = "updated" - lifecycle { - create_before_destroy = true - } -} -`, - }) - - p := simpleMockProvider() - p.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) { - s := req.PriorState.GetAttr("test_string").AsString() - if s == "current" { - resp.NewState = req.PriorState - return resp - } - // pretend the non-current instance has been deleted already - resp.NewState = cty.NullVal(req.PriorState.Type()) - return resp - } - - // Here we introduce a cycle via state which only shows up in the apply - // graph where the actual destroy instances are connected in the graph. - // This could happen for example when a user has an existing state with - // stored dependencies, and changes the config in such a way that - // contradicts the stored dependencies. - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceDeposed( - mustResourceInstanceAddr("test_object.a[0]").Resource, - states.DeposedKey("deposed"), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectTainted, - AttrsJSON: []byte(`{"test_string":"old"}`), - Dependencies: []addrs.ConfigResource{}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.a[0]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectTainted, - AttrsJSON: []byte(`{"test_string":"current"}`), - Dependencies: []addrs.ConfigResource{}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - _, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.NormalMode, - }) - assertNoErrors(t, diags) -} - -// make sure there are no cycles with changes around a provider configured via -// managed resources. -func TestContext2Plan_destroyWithResourceConfiguredProvider(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "test_object" "a" { - in = "a" -} - -provider "test" { - alias = "other" - in = test_object.a.out -} - -resource "test_object" "b" { - provider = test.other - in = "a" -} -`}) - - testProvider := &MockProvider{ - GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{ - Provider: providers.Schema{ - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "in": { - Type: cty.String, - Optional: true, - }, - }, - }, - }, - ResourceTypes: map[string]providers.Schema{ - "test_object": providers.Schema{ - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "in": { - Type: cty.String, - Optional: true, - }, - "out": { - Type: cty.Number, - Computed: true, - }, - }, - }, - }, - }, - }, - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(testProvider), - }, - }) - - // plan+apply to create the initial state - opts := SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)) - plan, diags := ctx.Plan(m, states.NewState(), opts) - assertNoErrors(t, diags) - state, diags := ctx.Apply(plan, m) - assertNoErrors(t, diags) - - // Resource changes which have dependencies across providers which - // themselves depend on resources can result in cycles. - // Because other_object transitively depends on the module resources - // through its provider, we trigger changes on both sides of this boundary - // to ensure we can create a valid plan. - // - // Try to replace both instances - addrA := mustResourceInstanceAddr("test_object.a") - addrB := mustResourceInstanceAddr(`test_object.b`) - opts.ForceReplace = []addrs.AbsResourceInstance{addrA, addrB} - - _, diags = ctx.Plan(m, state, opts) - assertNoErrors(t, diags) -} - -func TestContext2Plan_destroyPartialState(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "test_object" "a" { -} - -output "out" { - value = module.mod.out -} - -module "mod" { - source = "./mod" -} -`, - - "./mod/main.tf": ` -resource "test_object" "a" { - count = 2 - - lifecycle { - precondition { - # test_object_b has already been destroyed, so referencing the first - # instance must not fail during a destroy plan. - condition = test_object.b[0].test_string == "invalid" - error_message = "should not block destroy" - } - precondition { - # this failing condition should bot block a destroy plan - condition = !local.continue - error_message = "should not block destroy" - } - } -} - -resource "test_object" "b" { - count = 2 -} - -locals { - continue = true -} - -output "out" { - # the reference to test_object.b[0] may not be valid during a destroy plan, - # but should not fail. - value = local.continue ? test_object.a[1].test_string != "invalid" && test_object.b[0].test_string != "invalid" : false - - precondition { - # test_object_b has already been destroyed, so referencing the first - # instance must not fail during a destroy plan. - condition = test_object.b[0].test_string == "invalid" - error_message = "should not block destroy" - } - precondition { - # this failing condition should bot block a destroy plan - condition = test_object.a[0].test_string == "invalid" - error_message = "should not block destroy" - } -} -`}) - - p := simpleMockProvider() - - // This state could be the result of a failed destroy, leaving only 2 - // remaining instances. We want to be able to continue the destroy to - // remove everything without blocking on invalid references or failing - // conditions. - state := states.NewState() - mod := state.EnsureModule(addrs.RootModuleInstance.Child("mod", addrs.NoKey)) - mod.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.a[0]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectTainted, - AttrsJSON: []byte(`{"test_string":"current"}`), - Dependencies: []addrs.ConfigResource{}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - mod.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.a[1]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectTainted, - AttrsJSON: []byte(`{"test_string":"current"}`), - Dependencies: []addrs.ConfigResource{}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - _, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - assertNoErrors(t, diags) -} - -// Make sure the data sources in the prior state are serializeable even if -// there were an error in the plan. -func TestContext2Plan_dataSourceReadPlanError(t *testing.T) { - m, snap := testModuleWithSnapshot(t, "data-source-read-with-plan-error") - awsProvider := testProvider("aws") - testProvider := testProvider("test") - - testProvider.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { - resp.PlannedState = req.ProposedNewState - resp.Diagnostics = resp.Diagnostics.Append(errors.New("oops")) - return resp - } - - state := states.NewState() - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(awsProvider), - addrs.NewDefaultProvider("test"): testProviderFuncFixed(testProvider), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if !diags.HasErrors() { - t.Fatalf("expected plan error") - } - - // make sure we can serialize the plan even if there were an error - _, _, _, err := contextOptsForPlanViaFile(t, snap, plan) - if err != nil { - t.Fatalf("failed to round-trip through planfile: %s", err) - } -} diff --git a/internal/terraform/context_plan_test.go b/internal/terraform/context_plan_test.go deleted file mode 100644 index 9a2eb5f9cb60..000000000000 --- a/internal/terraform/context_plan_test.go +++ /dev/null @@ -1,6931 +0,0 @@ -package terraform - -import ( - "bytes" - "errors" - "fmt" - "os" - "reflect" - "sort" - "strings" - "sync" - "sync/atomic" - "testing" - - "github.com/davecgh/go-spew/spew" - "github.com/google/go-cmp/cmp" - "github.com/zclconf/go-cty/cty" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/configs/hcl2shim" - "github.com/hashicorp/terraform/internal/lang/marks" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/provisioners" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -func TestContext2Plan_basic(t *testing.T) { - m := testModule(t, "plan-good") - p := testProvider("aws") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - if l := len(plan.Changes.Resources); l < 2 { - t.Fatalf("wrong number of resources %d; want fewer than two\n%s", l, spew.Sdump(plan.Changes.Resources)) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - for _, r := range plan.Changes.Resources { - ric, err := r.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "aws_instance.bar": - foo := ric.After.GetAttr("foo").AsString() - if foo != "2" { - t.Fatalf("incorrect plan for 'bar': %#v", ric.After) - } - case "aws_instance.foo": - num, _ := ric.After.GetAttr("num").AsBigFloat().Int64() - if num != 2 { - t.Fatalf("incorrect plan for 'foo': %#v", ric.After) - } - default: - t.Fatal("unknown instance:", i) - } - } - - if !p.ValidateProviderConfigCalled { - t.Fatal("provider config was not checked before Configure") - } - -} - -func TestContext2Plan_createBefore_deposed(t *testing.T) { - m := testModule(t, "plan-cbd") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"baz","type":"aws_instance"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceDeposed( - mustResourceInstanceAddr("aws_instance.foo").Resource, - states.DeposedKey("00000001"), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - // the state should still show one deposed - expectedState := strings.TrimSpace(` - aws_instance.foo: (1 deposed) - ID = baz - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance - Deposed ID 1 = foo`) - - if plan.PriorState.String() != expectedState { - t.Fatalf("\nexpected: %q\ngot: %q\n", expectedState, plan.PriorState.String()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - type InstanceGen struct { - Addr string - DeposedKey states.DeposedKey - } - want := map[InstanceGen]bool{ - { - Addr: "aws_instance.foo", - }: true, - { - Addr: "aws_instance.foo", - DeposedKey: states.DeposedKey("00000001"), - }: true, - } - got := make(map[InstanceGen]bool) - changes := make(map[InstanceGen]*plans.ResourceInstanceChangeSrc) - - for _, change := range plan.Changes.Resources { - k := InstanceGen{ - Addr: change.Addr.String(), - DeposedKey: change.DeposedKey, - } - got[k] = true - changes[k] = change - } - if !reflect.DeepEqual(got, want) { - t.Fatalf("wrong resource instance object changes in plan\ngot: %s\nwant: %s", spew.Sdump(got), spew.Sdump(want)) - } - - { - ric, err := changes[InstanceGen{Addr: "aws_instance.foo"}].Decode(ty) - if err != nil { - t.Fatal(err) - } - - if got, want := ric.Action, plans.NoOp; got != want { - t.Errorf("current object change action is %s; want %s", got, want) - } - - // the existing instance should only have an unchanged id - expected, err := schema.CoerceValue(cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("baz"), - "type": cty.StringVal("aws_instance"), - })) - if err != nil { - t.Fatal(err) - } - - checkVals(t, expected, ric.After) - } - - { - ric, err := changes[InstanceGen{Addr: "aws_instance.foo", DeposedKey: states.DeposedKey("00000001")}].Decode(ty) - if err != nil { - t.Fatal(err) - } - - if got, want := ric.Action, plans.Delete; got != want { - t.Errorf("deposed object change action is %s; want %s", got, want) - } - } -} - -func TestContext2Plan_createBefore_maintainRoot(t *testing.T) { - m := testModule(t, "plan-cbd-maintain-root") - p := testProvider("aws") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - if !plan.PriorState.Empty() { - t.Fatal("expected empty prior state, got:", plan.PriorState) - } - - if len(plan.Changes.Resources) != 4 { - t.Error("expected 4 resource in plan, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - // these should all be creates - if res.Action != plans.Create { - t.Fatalf("unexpected action %s for %s", res.Action, res.Addr.String()) - } - } -} - -func TestContext2Plan_emptyDiff(t *testing.T) { - m := testModule(t, "plan-empty") - p := testProvider("aws") - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { - resp.PlannedState = req.ProposedNewState - return resp - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - if !plan.PriorState.Empty() { - t.Fatal("expected empty state, got:", plan.PriorState) - } - - if len(plan.Changes.Resources) != 2 { - t.Error("expected 2 resource in plan, got", len(plan.Changes.Resources)) - } - - actions := map[string]plans.Action{} - - for _, res := range plan.Changes.Resources { - actions[res.Addr.String()] = res.Action - } - - expected := map[string]plans.Action{ - "aws_instance.foo": plans.Create, - "aws_instance.bar": plans.Create, - } - if !cmp.Equal(expected, actions) { - t.Fatal(cmp.Diff(expected, actions)) - } -} - -func TestContext2Plan_escapedVar(t *testing.T) { - m := testModule(t, "plan-escaped-var") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - if len(plan.Changes.Resources) != 1 { - t.Error("expected 1 resource in plan, got", len(plan.Changes.Resources)) - } - - res := plan.Changes.Resources[0] - if res.Action != plans.Create { - t.Fatalf("expected resource creation, got %s", res.Action) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - expected := objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("bar-${baz}"), - "type": cty.UnknownVal(cty.String), - }) - - checkVals(t, expected, ric.After) -} - -func TestContext2Plan_minimal(t *testing.T) { - m := testModule(t, "plan-empty") - p := testProvider("aws") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - if !plan.PriorState.Empty() { - t.Fatal("expected empty state, got:", plan.PriorState) - } - - if len(plan.Changes.Resources) != 2 { - t.Error("expected 2 resource in plan, got", len(plan.Changes.Resources)) - } - - actions := map[string]plans.Action{} - - for _, res := range plan.Changes.Resources { - actions[res.Addr.String()] = res.Action - } - - expected := map[string]plans.Action{ - "aws_instance.foo": plans.Create, - "aws_instance.bar": plans.Create, - } - if !cmp.Equal(expected, actions) { - t.Fatal(cmp.Diff(expected, actions)) - } -} - -func TestContext2Plan_modules(t *testing.T) { - m := testModule(t, "plan-modules") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - if len(plan.Changes.Resources) != 3 { - t.Error("expected 3 resource in plan, got", len(plan.Changes.Resources)) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - expectFoo := objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("2"), - "type": cty.UnknownVal(cty.String), - }) - - expectNum := objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "num": cty.NumberIntVal(2), - "type": cty.UnknownVal(cty.String), - }) - - for _, res := range plan.Changes.Resources { - if res.Action != plans.Create { - t.Fatalf("expected resource creation, got %s", res.Action) - } - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - var expected cty.Value - switch i := ric.Addr.String(); i { - case "aws_instance.bar": - expected = expectFoo - case "aws_instance.foo": - expected = expectNum - case "module.child.aws_instance.foo": - expected = expectNum - default: - t.Fatal("unknown instance:", i) - } - - checkVals(t, expected, ric.After) - } -} -func TestContext2Plan_moduleExpand(t *testing.T) { - // Test a smattering of plan expansion behavior - m := testModule(t, "plan-modules-expand") - p := testProvider("aws") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - expected := map[string]struct{}{ - `aws_instance.foo["a"]`: {}, - `module.count_child[1].aws_instance.foo[0]`: {}, - `module.count_child[1].aws_instance.foo[1]`: {}, - `module.count_child[0].aws_instance.foo[0]`: {}, - `module.count_child[0].aws_instance.foo[1]`: {}, - `module.for_each_child["a"].aws_instance.foo[1]`: {}, - `module.for_each_child["a"].aws_instance.foo[0]`: {}, - } - - for _, res := range plan.Changes.Resources { - if res.Action != plans.Create { - t.Fatalf("expected resource creation, got %s", res.Action) - } - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - _, ok := expected[ric.Addr.String()] - if !ok { - t.Fatal("unexpected resource:", ric.Addr.String()) - } - delete(expected, ric.Addr.String()) - } - for addr := range expected { - t.Error("missing resource", addr) - } -} - -// GH-1475 -func TestContext2Plan_moduleCycle(t *testing.T) { - m := testModule(t, "plan-module-cycle") - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Computed: true}, - "some_input": {Type: cty.String, Optional: true}, - "type": {Type: cty.String, Computed: true}, - }, - }, - }, - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 2 { - t.Fatal("expected 2 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - if res.Action != plans.Create { - t.Fatalf("expected resource creation, got %s", res.Action) - } - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - var expected cty.Value - switch i := ric.Addr.String(); i { - case "aws_instance.b": - expected = objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "type": cty.UnknownVal(cty.String), - }) - case "aws_instance.c": - expected = objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "some_input": cty.UnknownVal(cty.String), - "type": cty.UnknownVal(cty.String), - }) - default: - t.Fatal("unknown instance:", i) - } - - checkVals(t, expected, ric.After) - } -} - -func TestContext2Plan_moduleDeadlock(t *testing.T) { - testCheckDeadlock(t, func() { - m := testModule(t, "plan-module-deadlock") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, err := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if err != nil { - t.Fatalf("err: %s", err) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - for _, res := range plan.Changes.Resources { - if res.Action != plans.Create { - t.Fatalf("expected resource creation, got %s", res.Action) - } - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - expected := objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "type": cty.UnknownVal(cty.String), - }) - switch i := ric.Addr.String(); i { - case "module.child.aws_instance.foo[0]": - case "module.child.aws_instance.foo[1]": - case "module.child.aws_instance.foo[2]": - default: - t.Fatal("unknown instance:", i) - } - - checkVals(t, expected, ric.After) - } - }) -} - -func TestContext2Plan_moduleInput(t *testing.T) { - m := testModule(t, "plan-module-input") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 2 { - t.Fatal("expected 2 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - if res.Action != plans.Create { - t.Fatalf("expected resource creation, got %s", res.Action) - } - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - var expected cty.Value - - switch i := ric.Addr.String(); i { - case "aws_instance.bar": - expected = objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("2"), - "type": cty.UnknownVal(cty.String), - }) - case "module.child.aws_instance.foo": - expected = objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("42"), - "type": cty.UnknownVal(cty.String), - }) - default: - t.Fatal("unknown instance:", i) - } - - checkVals(t, expected, ric.After) - } -} - -func TestContext2Plan_moduleInputComputed(t *testing.T) { - m := testModule(t, "plan-module-input-computed") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 2 { - t.Fatal("expected 2 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - if res.Action != plans.Create { - t.Fatalf("expected resource creation, got %s", res.Action) - } - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "aws_instance.bar": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.UnknownVal(cty.String), - "type": cty.UnknownVal(cty.String), - "compute": cty.StringVal("foo"), - }), ric.After) - case "module.child.aws_instance.foo": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.UnknownVal(cty.String), - "type": cty.UnknownVal(cty.String), - }), ric.After) - default: - t.Fatal("unknown instance:", i) - } - } -} - -func TestContext2Plan_moduleInputFromVar(t *testing.T) { - m := testModule(t, "plan-module-input-var") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "foo": &InputValue{ - Value: cty.StringVal("52"), - SourceType: ValueFromCaller, - }, - }, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 2 { - t.Fatal("expected 2 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - if res.Action != plans.Create { - t.Fatalf("expected resource creation, got %s", res.Action) - } - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "aws_instance.bar": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("2"), - "type": cty.UnknownVal(cty.String), - }), ric.After) - case "module.child.aws_instance.foo": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("52"), - "type": cty.UnknownVal(cty.String), - }), ric.After) - default: - t.Fatal("unknown instance:", i) - } - } -} - -func TestContext2Plan_moduleMultiVar(t *testing.T) { - m := testModule(t, "plan-module-multi-var") - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Computed: true}, - "foo": {Type: cty.String, Optional: true}, - "baz": {Type: cty.String, Optional: true}, - }, - }, - }, - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 5 { - t.Fatal("expected 5 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - if res.Action != plans.Create { - t.Fatalf("expected resource creation, got %s", res.Action) - } - - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "aws_instance.parent[0]": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - }), ric.After) - case "aws_instance.parent[1]": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - }), ric.After) - case "module.child.aws_instance.bar[0]": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "baz": cty.StringVal("baz"), - }), ric.After) - case "module.child.aws_instance.bar[1]": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "baz": cty.StringVal("baz"), - }), ric.After) - case "module.child.aws_instance.foo": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("baz,baz"), - }), ric.After) - default: - t.Fatal("unknown instance:", i) - } - } -} - -func TestContext2Plan_moduleOrphans(t *testing.T) { - m := testModule(t, "plan-modules-remove") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - state := states.NewState() - child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey)) - child.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"baz"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 2 { - t.Fatal("expected 2 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "aws_instance.foo": - if res.Action != plans.Create { - t.Fatalf("expected resource creation, got %s", res.Action) - } - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "num": cty.NumberIntVal(2), - "type": cty.UnknownVal(cty.String), - }), ric.After) - case "module.child.aws_instance.foo": - if res.Action != plans.Delete { - t.Fatalf("expected resource delete, got %s", res.Action) - } - default: - t.Fatal("unknown instance:", i) - } - } - - expectedState := ` -module.child: - aws_instance.foo: - ID = baz - provider = provider["registry.terraform.io/hashicorp/aws"]` - - if plan.PriorState.String() != expectedState { - t.Fatalf("\nexpected state: %q\n\ngot: %q", expectedState, plan.PriorState.String()) - } -} - -// https://github.com/hashicorp/terraform/issues/3114 -func TestContext2Plan_moduleOrphansWithProvisioner(t *testing.T) { - m := testModule(t, "plan-modules-remove-provisioners") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - pr := testProvisioner() - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.top").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"top","type":"aws_instance"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - child1 := state.EnsureModule(addrs.RootModuleInstance.Child("parent", addrs.NoKey).Child("child1", addrs.NoKey)) - child1.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"baz","type":"aws_instance"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - child2 := state.EnsureModule(addrs.RootModuleInstance.Child("parent", addrs.NoKey).Child("child2", addrs.NoKey)) - child2.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"baz","type":"aws_instance"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Provisioners: map[string]provisioners.Factory{ - "shell": testProvisionerFuncFixed(pr), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 3 { - t.Error("expected 3 planned resources, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "module.parent.module.child1.aws_instance.foo": - if res.Action != plans.Delete { - t.Fatalf("expected resource Delete, got %s", res.Action) - } - case "module.parent.module.child2.aws_instance.foo": - if res.Action != plans.Delete { - t.Fatalf("expected resource Delete, got %s", res.Action) - } - case "aws_instance.top": - if res.Action != plans.NoOp { - t.Fatalf("expected no changes, got %s", res.Action) - } - default: - t.Fatalf("unknown instance: %s\nafter: %#v", i, hcl2shim.ConfigValueFromHCL2(ric.After)) - } - } - - expectedState := `aws_instance.top: - ID = top - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance - -module.parent.child1: - aws_instance.foo: - ID = baz - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance -module.parent.child2: - aws_instance.foo: - ID = baz - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance` - - if expectedState != plan.PriorState.String() { - t.Fatalf("\nexpect state:\n%s\n\ngot state:\n%s\n", expectedState, plan.PriorState.String()) - } -} - -func TestContext2Plan_moduleProviderInherit(t *testing.T) { - var l sync.Mutex - var calls []string - - m := testModule(t, "plan-module-provider-inherit") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): func() (providers.Interface, error) { - l.Lock() - defer l.Unlock() - - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - Provider: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "from": {Type: cty.String, Optional: true}, - }, - }, - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "from": {Type: cty.String, Optional: true}, - }, - }, - }, - }) - p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) { - from := req.Config.GetAttr("from") - if from.IsNull() || from.AsString() != "root" { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("not root")) - } - - return - } - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { - from := req.Config.GetAttr("from").AsString() - - l.Lock() - defer l.Unlock() - calls = append(calls, from) - return testDiffFn(req) - } - return p, nil - }, - }, - }) - - _, err := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if err != nil { - t.Fatalf("err: %s", err) - } - - actual := calls - sort.Strings(actual) - expected := []string{"child", "root"} - if !reflect.DeepEqual(actual, expected) { - t.Fatalf("bad: %#v", actual) - } -} - -// This tests (for GH-11282) that deeply nested modules properly inherit -// configuration. -func TestContext2Plan_moduleProviderInheritDeep(t *testing.T) { - var l sync.Mutex - - m := testModule(t, "plan-module-provider-inherit-deep") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): func() (providers.Interface, error) { - l.Lock() - defer l.Unlock() - - var from string - p := testProvider("aws") - - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - Provider: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "from": {Type: cty.String, Optional: true}, - }, - }, - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{}, - }, - }, - }) - - p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) { - v := req.Config.GetAttr("from") - if v.IsNull() || v.AsString() != "root" { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("not root")) - } - from = v.AsString() - - return - } - - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { - if from != "root" { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("bad resource")) - return - } - - return testDiffFn(req) - } - return p, nil - }, - }, - }) - - _, err := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if err != nil { - t.Fatalf("err: %s", err) - } -} - -func TestContext2Plan_moduleProviderDefaultsVar(t *testing.T) { - var l sync.Mutex - var calls []string - - m := testModule(t, "plan-module-provider-defaults-var") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): func() (providers.Interface, error) { - l.Lock() - defer l.Unlock() - - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - Provider: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "to": {Type: cty.String, Optional: true}, - "from": {Type: cty.String, Optional: true}, - }, - }, - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "from": {Type: cty.String, Optional: true}, - }, - }, - }, - }) - p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) { - var buf bytes.Buffer - from := req.Config.GetAttr("from") - if !from.IsNull() { - buf.WriteString(from.AsString() + "\n") - } - to := req.Config.GetAttr("to") - if !to.IsNull() { - buf.WriteString(to.AsString() + "\n") - } - - l.Lock() - defer l.Unlock() - calls = append(calls, buf.String()) - return - } - - return p, nil - }, - }, - }) - - _, err := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "foo": &InputValue{ - Value: cty.StringVal("root"), - SourceType: ValueFromCaller, - }, - }, - }) - if err != nil { - t.Fatalf("err: %s", err) - } - - expected := []string{ - "child\nchild\n", - "root\n", - } - sort.Strings(calls) - if !reflect.DeepEqual(calls, expected) { - t.Fatalf("expected:\n%#v\ngot:\n%#v\n", expected, calls) - } -} - -func TestContext2Plan_moduleProviderVar(t *testing.T) { - m := testModule(t, "plan-module-provider-var") - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - Provider: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "value": {Type: cty.String, Optional: true}, - }, - }, - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "value": {Type: cty.String, Optional: true}, - }, - }, - }, - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 1 { - t.Fatal("expected 1 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - if res.Action != plans.Create { - t.Fatalf("expected resource creation, got %s", res.Action) - } - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "module.child.aws_instance.test": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "value": cty.StringVal("hello"), - }), ric.After) - default: - t.Fatal("unknown instance:", i) - } - } -} - -func TestContext2Plan_moduleVar(t *testing.T) { - m := testModule(t, "plan-module-var") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 2 { - t.Fatal("expected 2 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - if res.Action != plans.Create { - t.Fatalf("expected resource creation, got %s", res.Action) - } - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - var expected cty.Value - - switch i := ric.Addr.String(); i { - case "aws_instance.bar": - expected = objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("2"), - "type": cty.UnknownVal(cty.String), - }) - case "module.child.aws_instance.foo": - expected = objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "num": cty.NumberIntVal(2), - "type": cty.UnknownVal(cty.String), - }) - default: - t.Fatal("unknown instance:", i) - } - - checkVals(t, expected, ric.After) - } -} - -func TestContext2Plan_moduleVarWrongTypeBasic(t *testing.T) { - m := testModule(t, "plan-module-wrong-var-type") - p := testProvider("aws") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - _, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if !diags.HasErrors() { - t.Fatalf("succeeded; want errors") - } -} - -func TestContext2Plan_moduleVarWrongTypeNested(t *testing.T) { - m := testModule(t, "plan-module-wrong-var-type-nested") - p := testProvider("null") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("null"): testProviderFuncFixed(p), - }, - }) - - _, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if !diags.HasErrors() { - t.Fatalf("succeeded; want errors") - } -} - -func TestContext2Plan_moduleVarWithDefaultValue(t *testing.T) { - m := testModule(t, "plan-module-var-with-default-value") - p := testProvider("null") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("null"): testProviderFuncFixed(p), - }, - }) - - _, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } -} - -func TestContext2Plan_moduleVarComputed(t *testing.T) { - m := testModule(t, "plan-module-var-computed") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 2 { - t.Fatal("expected 2 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - if res.Action != plans.Create { - t.Fatalf("expected resource creation, got %s", res.Action) - } - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "aws_instance.bar": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.UnknownVal(cty.String), - "type": cty.UnknownVal(cty.String), - }), ric.After) - case "module.child.aws_instance.foo": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.UnknownVal(cty.String), - "type": cty.UnknownVal(cty.String), - "compute": cty.StringVal("foo"), - }), ric.After) - default: - t.Fatal("unknown instance:", i) - } - } -} - -func TestContext2Plan_preventDestroy_bad(t *testing.T) { - m := testModule(t, "plan-prevent-destroy-bad") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"i-abc123"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, err := ctx.Plan(m, state, DefaultPlanOpts) - - expectedErr := "aws_instance.foo has lifecycle.prevent_destroy" - if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) { - if plan != nil { - t.Logf(legacyDiffComparisonString(plan.Changes)) - } - t.Fatalf("expected err would contain %q\nerr: %s", expectedErr, err) - } -} - -func TestContext2Plan_preventDestroy_good(t *testing.T) { - m := testModule(t, "plan-prevent-destroy-good") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"i-abc123","type":"aws_instance"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - if !plan.Changes.Empty() { - t.Fatalf("expected no changes, got %#v\n", plan.Changes) - } -} - -func TestContext2Plan_preventDestroy_countBad(t *testing.T) { - m := testModule(t, "plan-prevent-destroy-count-bad") - p := testProvider("aws") - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[0]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"i-abc123"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[1]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"i-abc345"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, err := ctx.Plan(m, state, DefaultPlanOpts) - - expectedErr := "aws_instance.foo[1] has lifecycle.prevent_destroy" - if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) { - if plan != nil { - t.Logf(legacyDiffComparisonString(plan.Changes)) - } - t.Fatalf("expected err would contain %q\nerr: %s", expectedErr, err) - } -} - -func TestContext2Plan_preventDestroy_countGood(t *testing.T) { - m := testModule(t, "plan-prevent-destroy-count-good") - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "current": {Type: cty.String, Optional: true}, - "id": {Type: cty.String, Computed: true}, - }, - }, - }, - }) - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[0]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"i-abc123"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[1]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"i-abc345"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - if plan.Changes.Empty() { - t.Fatalf("Expected non-empty plan, got %s", legacyDiffComparisonString(plan.Changes)) - } -} - -func TestContext2Plan_preventDestroy_countGoodNoChange(t *testing.T) { - m := testModule(t, "plan-prevent-destroy-count-good") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "current": {Type: cty.String, Optional: true}, - "type": {Type: cty.String, Optional: true, Computed: true}, - "id": {Type: cty.String, Computed: true}, - }, - }, - }, - }) - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[0]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"i-abc123","current":"0","type":"aws_instance"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - if !plan.Changes.Empty() { - t.Fatalf("Expected empty plan, got %s", legacyDiffComparisonString(plan.Changes)) - } -} - -func TestContext2Plan_preventDestroy_destroyPlan(t *testing.T) { - m := testModule(t, "plan-prevent-destroy-good") - p := testProvider("aws") - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"i-abc123"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - - expectedErr := "aws_instance.foo has lifecycle.prevent_destroy" - if !strings.Contains(fmt.Sprintf("%s", diags.Err()), expectedErr) { - if plan != nil { - t.Logf(legacyDiffComparisonString(plan.Changes)) - } - t.Fatalf("expected diagnostics would contain %q\nactual diags: %s", expectedErr, diags.Err()) - } -} - -func TestContext2Plan_provisionerCycle(t *testing.T) { - m := testModule(t, "plan-provisioner-cycle") - p := testProvider("aws") - pr := testProvisioner() - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Provisioners: map[string]provisioners.Factory{ - "local-exec": testProvisionerFuncFixed(pr), - }, - }) - - _, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if !diags.HasErrors() { - t.Fatalf("succeeded; want errors") - } -} - -func TestContext2Plan_computed(t *testing.T) { - m := testModule(t, "plan-computed") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 2 { - t.Fatal("expected 2 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - if res.Action != plans.Create { - t.Fatalf("expected resource creation, got %s", res.Action) - } - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "aws_instance.bar": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.UnknownVal(cty.String), - "type": cty.UnknownVal(cty.String), - }), ric.After) - case "aws_instance.foo": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.UnknownVal(cty.String), - "num": cty.NumberIntVal(2), - "type": cty.UnknownVal(cty.String), - "compute": cty.StringVal("foo"), - }), ric.After) - default: - t.Fatal("unknown instance:", i) - } - } -} - -func TestContext2Plan_blockNestingGroup(t *testing.T) { - m := testModule(t, "plan-block-nesting-group") - p := testProvider("test") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test": { - BlockTypes: map[string]*configschema.NestedBlock{ - "blah": { - Nesting: configschema.NestingGroup, - Block: configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "baz": {Type: cty.String, Required: true}, - }, - }, - }, - }, - }, - }, - }) - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse { - return providers.PlanResourceChangeResponse{ - PlannedState: req.ProposedNewState, - } - } - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - if got, want := 1, len(plan.Changes.Resources); got != want { - t.Fatalf("wrong number of planned resource changes %d; want %d\n%s", got, want, spew.Sdump(plan.Changes.Resources)) - } - - if !p.PlanResourceChangeCalled { - t.Fatalf("PlanResourceChange was not called at all") - } - - got := p.PlanResourceChangeRequest - want := providers.PlanResourceChangeRequest{ - TypeName: "test", - - // Because block type "blah" is defined as NestingGroup, we get a non-null - // value for it with null nested attributes, rather than the "blah" object - // itself being null, when there's no "blah" block in the config at all. - // - // This represents the situation where the remote service _always_ creates - // a single "blah", regardless of whether the block is present, but when - // the block _is_ present the user can override some aspects of it. The - // absense of the block means "use the defaults", in that case. - Config: cty.ObjectVal(map[string]cty.Value{ - "blah": cty.ObjectVal(map[string]cty.Value{ - "baz": cty.NullVal(cty.String), - }), - }), - ProposedNewState: cty.ObjectVal(map[string]cty.Value{ - "blah": cty.ObjectVal(map[string]cty.Value{ - "baz": cty.NullVal(cty.String), - }), - }), - } - if !cmp.Equal(got, want, valueTrans) { - t.Errorf("wrong PlanResourceChange request\n%s", cmp.Diff(got, want, valueTrans)) - } -} - -func TestContext2Plan_computedDataResource(t *testing.T) { - m := testModule(t, "plan-computed-data-resource") - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "num": {Type: cty.String, Optional: true}, - "compute": {Type: cty.String, Optional: true}, - "foo": {Type: cty.String, Computed: true}, - }, - }, - }, - DataSources: map[string]*configschema.Block{ - "aws_vpc": { - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - schema := p.GetProviderSchemaResponse.DataSources["aws_vpc"].Block - ty := schema.ImpliedType() - - if rc := plan.Changes.ResourceInstance(addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "aws_instance", Name: "foo"}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)); rc == nil { - t.Fatalf("missing diff for aws_instance.foo") - } - rcs := plan.Changes.ResourceInstance(addrs.Resource{ - Mode: addrs.DataResourceMode, - Type: "aws_vpc", - Name: "bar", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)) - if rcs == nil { - t.Fatalf("missing diff for data.aws_vpc.bar") - } - - rc, err := rcs.Decode(ty) - if err != nil { - t.Fatal(err) - } - - checkVals(t, - cty.ObjectVal(map[string]cty.Value{ - "foo": cty.UnknownVal(cty.String), - }), - rc.After, - ) - if got, want := rc.ActionReason, plans.ResourceInstanceReadBecauseConfigUnknown; got != want { - t.Errorf("wrong ActionReason\ngot: %s\nwant: %s", got, want) - } -} - -func TestContext2Plan_computedInFunction(t *testing.T) { - m := testModule(t, "plan-computed-in-function") - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "attr": {Type: cty.Number, Optional: true}, - }, - }, - }, - DataSources: map[string]*configschema.Block{ - "aws_data_source": { - Attributes: map[string]*configschema.Attribute{ - "computed": {Type: cty.List(cty.String), Computed: true}, - }, - }, - }, - }) - p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{ - State: cty.ObjectVal(map[string]cty.Value{ - "computed": cty.ListVal([]cty.Value{ - cty.StringVal("foo"), - }), - }), - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := ctx.Validate(m) - assertNoErrors(t, diags) - - _, diags = ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - if !p.ReadDataSourceCalled { - t.Fatalf("ReadDataSource was not called on provider during plan; should've been called") - } -} - -func TestContext2Plan_computedDataCountResource(t *testing.T) { - m := testModule(t, "plan-computed-data-count") - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "num": {Type: cty.String, Optional: true}, - "compute": {Type: cty.String, Optional: true}, - "foo": {Type: cty.String, Computed: true}, - }, - }, - }, - DataSources: map[string]*configschema.Block{ - "aws_vpc": { - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - // make sure we created 3 "bar"s - for i := 0; i < 3; i++ { - addr := addrs.Resource{ - Mode: addrs.DataResourceMode, - Type: "aws_vpc", - Name: "bar", - }.Instance(addrs.IntKey(i)).Absolute(addrs.RootModuleInstance) - - if rcs := plan.Changes.ResourceInstance(addr); rcs == nil { - t.Fatalf("missing changes for %s", addr) - } - } -} - -func TestContext2Plan_localValueCount(t *testing.T) { - m := testModule(t, "plan-local-value-count") - p := testProvider("test") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - // make sure we created 3 "foo"s - for i := 0; i < 3; i++ { - addr := addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_resource", - Name: "foo", - }.Instance(addrs.IntKey(i)).Absolute(addrs.RootModuleInstance) - - if rcs := plan.Changes.ResourceInstance(addr); rcs == nil { - t.Fatalf("missing changes for %s", addr) - } - } -} - -func TestContext2Plan_dataResourceBecomesComputed(t *testing.T) { - m := testModule(t, "plan-data-resource-becomes-computed") - p := testProvider("aws") - - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - "computed": {Type: cty.String, Computed: true}, - }, - }, - }, - DataSources: map[string]*configschema.Block{ - "aws_data_source": { - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Computed: true}, - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - }) - - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse { - fooVal := req.ProposedNewState.GetAttr("foo") - return providers.PlanResourceChangeResponse{ - PlannedState: cty.ObjectVal(map[string]cty.Value{ - "foo": fooVal, - "computed": cty.UnknownVal(cty.String), - }), - PlannedPrivate: req.PriorPrivate, - } - } - - schema := p.GetProviderSchemaResponse.DataSources["aws_data_source"].Block - ty := schema.ImpliedType() - - p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{ - // This should not be called, because the configuration for the - // data resource contains an unknown value for "foo". - Diagnostics: tfdiags.Diagnostics(nil).Append(fmt.Errorf("ReadDataSource called, but should not have been")), - } - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("data.aws_data_source.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"i-abc123","foo":"baz"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors during plan: %s", diags.Err()) - } - - rcs := plan.Changes.ResourceInstance(addrs.Resource{ - Mode: addrs.DataResourceMode, - Type: "aws_data_source", - Name: "foo", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)) - if rcs == nil { - t.Logf("full changeset: %s", spew.Sdump(plan.Changes)) - t.Fatalf("missing diff for data.aws_data_resource.foo") - } - - rc, err := rcs.Decode(ty) - if err != nil { - t.Fatal(err) - } - - if got, want := rc.ActionReason, plans.ResourceInstanceReadBecauseConfigUnknown; got != want { - t.Errorf("wrong ActionReason\ngot: %s\nwant: %s", got, want) - } - - // foo should now be unknown - foo := rc.After.GetAttr("foo") - if foo.IsKnown() { - t.Fatalf("foo should be unknown, got %#v", foo) - } -} - -func TestContext2Plan_computedList(t *testing.T) { - m := testModule(t, "plan-computed-list") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "compute": {Type: cty.String, Optional: true}, - "foo": {Type: cty.String, Optional: true}, - "num": {Type: cty.String, Optional: true}, - "list": {Type: cty.List(cty.String), Computed: true}, - }, - }, - }, - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 2 { - t.Fatal("expected 2 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - if res.Action != plans.Create { - t.Fatalf("expected resource creation, got %s", res.Action) - } - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "aws_instance.bar": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "foo": cty.UnknownVal(cty.String), - }), ric.After) - case "aws_instance.foo": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "list": cty.UnknownVal(cty.List(cty.String)), - "num": cty.NumberIntVal(2), - "compute": cty.StringVal("list.#"), - }), ric.After) - default: - t.Fatal("unknown instance:", i) - } - } -} - -// GH-8695. This tests that you can index into a computed list on a -// splatted resource. -func TestContext2Plan_computedMultiIndex(t *testing.T) { - m := testModule(t, "plan-computed-multi-index") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "compute": {Type: cty.String, Optional: true}, - "foo": {Type: cty.List(cty.String), Optional: true}, - "ip": {Type: cty.List(cty.String), Computed: true}, - }, - }, - }, - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 3 { - t.Fatal("expected 3 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - if res.Action != plans.Create { - t.Fatalf("expected resource creation, got %s", res.Action) - } - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "aws_instance.foo[0]": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "ip": cty.UnknownVal(cty.List(cty.String)), - "foo": cty.NullVal(cty.List(cty.String)), - "compute": cty.StringVal("ip.#"), - }), ric.After) - case "aws_instance.foo[1]": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "ip": cty.UnknownVal(cty.List(cty.String)), - "foo": cty.NullVal(cty.List(cty.String)), - "compute": cty.StringVal("ip.#"), - }), ric.After) - case "aws_instance.bar[0]": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "foo": cty.UnknownVal(cty.List(cty.String)), - }), ric.After) - default: - t.Fatal("unknown instance:", i) - } - } -} - -func TestContext2Plan_count(t *testing.T) { - m := testModule(t, "plan-count") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 6 { - t.Fatal("expected 6 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - if res.Action != plans.Create { - t.Fatalf("expected resource creation, got %s", res.Action) - } - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "aws_instance.bar": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("foo,foo,foo,foo,foo"), - "type": cty.UnknownVal(cty.String), - }), ric.After) - case "aws_instance.foo[0]": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("foo"), - "type": cty.UnknownVal(cty.String), - }), ric.After) - case "aws_instance.foo[1]": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("foo"), - "type": cty.UnknownVal(cty.String), - }), ric.After) - case "aws_instance.foo[2]": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("foo"), - "type": cty.UnknownVal(cty.String), - }), ric.After) - case "aws_instance.foo[3]": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("foo"), - "type": cty.UnknownVal(cty.String), - }), ric.After) - case "aws_instance.foo[4]": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("foo"), - "type": cty.UnknownVal(cty.String), - }), ric.After) - default: - t.Fatal("unknown instance:", i) - } - } -} - -func TestContext2Plan_countComputed(t *testing.T) { - m := testModule(t, "plan-count-computed") - p := testProvider("aws") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - _, err := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if err == nil { - t.Fatal("should error") - } -} - -func TestContext2Plan_countComputedModule(t *testing.T) { - m := testModule(t, "plan-count-computed-module") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - _, err := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - - expectedErr := `The "count" value depends on resource attributes` - if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) { - t.Fatalf("expected err would contain %q\nerr: %s\n", - expectedErr, err) - } -} - -func TestContext2Plan_countModuleStatic(t *testing.T) { - m := testModule(t, "plan-count-module-static") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 3 { - t.Fatal("expected 3 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - if res.Action != plans.Create { - t.Fatalf("expected resource creation, got %s", res.Action) - } - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "module.child.aws_instance.foo[0]": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "type": cty.UnknownVal(cty.String), - }), ric.After) - case "module.child.aws_instance.foo[1]": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "type": cty.UnknownVal(cty.String), - }), ric.After) - case "module.child.aws_instance.foo[2]": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "type": cty.UnknownVal(cty.String), - }), ric.After) - default: - t.Fatal("unknown instance:", i) - } - } -} - -func TestContext2Plan_countModuleStaticGrandchild(t *testing.T) { - m := testModule(t, "plan-count-module-static-grandchild") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 3 { - t.Fatal("expected 3 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - if res.Action != plans.Create { - t.Fatalf("expected resource creation, got %s", res.Action) - } - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "module.child.module.child.aws_instance.foo[0]": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "type": cty.UnknownVal(cty.String), - }), ric.After) - case "module.child.module.child.aws_instance.foo[1]": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "type": cty.UnknownVal(cty.String), - }), ric.After) - case "module.child.module.child.aws_instance.foo[2]": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "type": cty.UnknownVal(cty.String), - }), ric.After) - default: - t.Fatal("unknown instance:", i) - } - } -} - -func TestContext2Plan_countIndex(t *testing.T) { - m := testModule(t, "plan-count-index") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 2 { - t.Fatal("expected 2 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - if res.Action != plans.Create { - t.Fatalf("expected resource creation, got %s", res.Action) - } - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "aws_instance.foo[0]": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("0"), - "type": cty.UnknownVal(cty.String), - }), ric.After) - case "aws_instance.foo[1]": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("1"), - "type": cty.UnknownVal(cty.String), - }), ric.After) - default: - t.Fatal("unknown instance:", i) - } - } -} - -func TestContext2Plan_countVar(t *testing.T) { - m := testModule(t, "plan-count-var") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "instance_count": &InputValue{ - Value: cty.StringVal("3"), - SourceType: ValueFromCaller, - }, - }, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 4 { - t.Fatal("expected 4 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - if res.Action != plans.Create { - t.Fatalf("expected resource creation, got %s", res.Action) - } - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "aws_instance.bar": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("foo,foo,foo"), - "type": cty.UnknownVal(cty.String), - }), ric.After) - case "aws_instance.foo[0]": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("foo"), - "type": cty.UnknownVal(cty.String), - }), ric.After) - case "aws_instance.foo[1]": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("foo"), - "type": cty.UnknownVal(cty.String), - }), ric.After) - case "aws_instance.foo[2]": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("foo"), - "type": cty.UnknownVal(cty.String), - }), ric.After) - default: - t.Fatal("unknown instance:", i) - } - } -} - -func TestContext2Plan_countZero(t *testing.T) { - m := testModule(t, "plan-count-zero") - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.DynamicPseudoType, Optional: true}, - }, - }, - }, - }) - - // This schema contains a DynamicPseudoType, and therefore can't go through any shim functions - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { - resp.PlannedState = req.ProposedNewState - resp.PlannedPrivate = req.PriorPrivate - return resp - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 1 { - t.Fatal("expected 1 changes, got", len(plan.Changes.Resources)) - } - - res := plan.Changes.Resources[0] - - if res.Action != plans.Create { - t.Fatalf("expected resource creation, got %s", res.Action) - } - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - expected := cty.TupleVal(nil) - - foo := ric.After.GetAttr("foo") - - if !cmp.Equal(expected, foo, valueComparer) { - t.Fatal(cmp.Diff(expected, foo, valueComparer)) - } -} - -func TestContext2Plan_countOneIndex(t *testing.T) { - m := testModule(t, "plan-count-one-index") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 2 { - t.Fatal("expected 2 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - if res.Action != plans.Create { - t.Fatalf("expected resource creation, got %s", res.Action) - } - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "aws_instance.bar": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("foo"), - "type": cty.UnknownVal(cty.String), - }), ric.After) - case "aws_instance.foo[0]": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("foo"), - "type": cty.UnknownVal(cty.String), - }), ric.After) - default: - t.Fatal("unknown instance:", i) - } - } -} - -func TestContext2Plan_countDecreaseToOne(t *testing.T) { - m := testModule(t, "plan-count-dec") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[0]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar","foo":"foo","type":"aws_instance"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[1]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[2]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 4 { - t.Fatal("expected 4 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "aws_instance.bar": - if res.Action != plans.Create { - t.Fatalf("expected resource create, got %s", res.Action) - } - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("bar"), - "type": cty.UnknownVal(cty.String), - }), ric.After) - case "aws_instance.foo": - if res.Action != plans.NoOp { - t.Fatalf("resource %s should be unchanged", i) - } - case "aws_instance.foo[1]": - if res.Action != plans.Delete { - t.Fatalf("expected resource delete, got %s", res.Action) - } - case "aws_instance.foo[2]": - if res.Action != plans.Delete { - t.Fatalf("expected resource delete, got %s", res.Action) - } - default: - t.Fatal("unknown instance:", i) - } - } - - expectedState := `aws_instance.foo: - ID = bar - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = foo - type = aws_instance -aws_instance.foo.1: - ID = bar - provider = provider["registry.terraform.io/hashicorp/aws"] -aws_instance.foo.2: - ID = bar - provider = provider["registry.terraform.io/hashicorp/aws"]` - - if plan.PriorState.String() != expectedState { - t.Fatalf("epected state:\n%q\n\ngot state:\n%q\n", expectedState, plan.PriorState.String()) - } -} - -func TestContext2Plan_countIncreaseFromNotSet(t *testing.T) { - m := testModule(t, "plan-count-inc") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar","type":"aws_instance","foo":"foo"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 4 { - t.Fatal("expected 4 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "aws_instance.bar": - if res.Action != plans.Create { - t.Fatalf("expected resource create, got %s", res.Action) - } - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("bar"), - "type": cty.UnknownVal(cty.String), - }), ric.After) - case "aws_instance.foo[0]": - if res.Action != plans.NoOp { - t.Fatalf("resource %s should be unchanged", i) - } - case "aws_instance.foo[1]": - if res.Action != plans.Create { - t.Fatalf("expected resource create, got %s", res.Action) - } - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("foo"), - "type": cty.UnknownVal(cty.String), - }), ric.After) - case "aws_instance.foo[2]": - if res.Action != plans.Create { - t.Fatalf("expected resource create, got %s", res.Action) - } - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("foo"), - "type": cty.UnknownVal(cty.String), - }), ric.After) - default: - t.Fatal("unknown instance:", i) - } - } -} - -func TestContext2Plan_countIncreaseFromOne(t *testing.T) { - m := testModule(t, "plan-count-inc") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[0]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar","foo":"foo","type":"aws_instance"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 4 { - t.Fatal("expected 4 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "aws_instance.bar": - if res.Action != plans.Create { - t.Fatalf("expected resource create, got %s", res.Action) - } - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("bar"), - "type": cty.UnknownVal(cty.String), - }), ric.After) - case "aws_instance.foo[0]": - if res.Action != plans.NoOp { - t.Fatalf("resource %s should be unchanged", i) - } - case "aws_instance.foo[1]": - if res.Action != plans.Create { - t.Fatalf("expected resource create, got %s", res.Action) - } - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("foo"), - "type": cty.UnknownVal(cty.String), - }), ric.After) - case "aws_instance.foo[2]": - if res.Action != plans.Create { - t.Fatalf("expected resource create, got %s", res.Action) - } - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("foo"), - "type": cty.UnknownVal(cty.String), - }), ric.After) - default: - t.Fatal("unknown instance:", i) - } - } -} - -// https://github.com/PeoplePerHour/terraform/pull/11 -// -// This tests a case where both a "resource" and "resource.0" are in -// the state file, which apparently is a reasonable backwards compatibility -// concern found in the above 3rd party repo. -func TestContext2Plan_countIncreaseFromOneCorrupted(t *testing.T) { - m := testModule(t, "plan-count-inc") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar","foo":"foo","type":"aws_instance"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[0]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar","foo":"foo","type":"aws_instance"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 5 { - t.Fatal("expected 5 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "aws_instance.bar": - if res.Action != plans.Create { - t.Fatalf("expected resource create, got %s", res.Action) - } - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("bar"), - "type": cty.UnknownVal(cty.String), - }), ric.After) - case "aws_instance.foo": - if res.Action != plans.Delete { - t.Fatalf("resource %s should be removed", i) - } - case "aws_instance.foo[0]": - if res.Action != plans.NoOp { - t.Fatalf("resource %s should be unchanged", i) - } - case "aws_instance.foo[1]": - if res.Action != plans.Create { - t.Fatalf("expected resource create, got %s", res.Action) - } - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("foo"), - "type": cty.UnknownVal(cty.String), - }), ric.After) - case "aws_instance.foo[2]": - if res.Action != plans.Create { - t.Fatalf("expected resource create, got %s", res.Action) - } - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("foo"), - "type": cty.UnknownVal(cty.String), - }), ric.After) - default: - t.Fatal("unknown instance:", i) - } - } -} - -// A common pattern in TF configs is to have a set of resources with the same -// count and to use count.index to create correspondences between them: -// -// foo_id = "${foo.bar.*.id[count.index]}" -// -// This test is for the situation where some instances already exist and the -// count is increased. In that case, we should see only the create diffs -// for the new instances and not any update diffs for the existing ones. -func TestContext2Plan_countIncreaseWithSplatReference(t *testing.T) { - m := testModule(t, "plan-count-splat-reference") - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "name": {Type: cty.String, Optional: true}, - "foo_name": {Type: cty.String, Optional: true}, - "id": {Type: cty.String, Computed: true}, - }, - }, - }, - }) - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[0]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar","name":"foo 0"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[1]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar","name":"foo 1"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar[0]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar","foo_name":"foo 0"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar[1]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar","foo_name":"foo 1"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 6 { - t.Fatal("expected 6 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "aws_instance.bar[0]", "aws_instance.bar[1]", "aws_instance.foo[0]", "aws_instance.foo[1]": - if res.Action != plans.NoOp { - t.Fatalf("resource %s should be unchanged", i) - } - case "aws_instance.bar[2]": - if res.Action != plans.Create { - t.Fatalf("expected resource create, got %s", res.Action) - } - // The instance ID changed, so just check that the name updated - if ric.After.GetAttr("foo_name") != cty.StringVal("foo 2") { - t.Fatalf("resource %s attr \"foo_name\" should be changed", i) - } - case "aws_instance.foo[2]": - if res.Action != plans.Create { - t.Fatalf("expected resource create, got %s", res.Action) - } - // The instance ID changed, so just check that the name updated - if ric.After.GetAttr("name") != cty.StringVal("foo 2") { - t.Fatalf("resource %s attr \"name\" should be changed", i) - } - default: - t.Fatal("unknown instance:", i) - } - } -} - -func TestContext2Plan_forEach(t *testing.T) { - m := testModule(t, "plan-for-each") - p := testProvider("aws") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 8 { - t.Fatal("expected 8 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - if res.Action != plans.Create { - t.Fatalf("expected resource creation, got %s", res.Action) - } - _, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - } -} - -func TestContext2Plan_forEachUnknownValue(t *testing.T) { - // This module has a variable defined, but it's value is unknown. We - // expect this to produce an error, but not to panic. - m := testModule(t, "plan-for-each-unknown-value") - p := testProvider("aws") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - _, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "foo": { - Value: cty.UnknownVal(cty.String), - SourceType: ValueFromCLIArg, - }, - }, - }) - if !diags.HasErrors() { - // Should get this error: - // Invalid for_each argument: The "for_each" value depends on resource attributes that cannot be determined until apply... - t.Fatal("succeeded; want errors") - } - - gotErrStr := diags.Err().Error() - wantErrStr := "Invalid for_each argument" - if !strings.Contains(gotErrStr, wantErrStr) { - t.Fatalf("missing expected error\ngot: %s\n\nwant: error containing %q", gotErrStr, wantErrStr) - } - - // We should have a diagnostic that is marked as being caused by unknown - // values. - for _, diag := range diags { - if tfdiags.DiagnosticCausedByUnknown(diag) { - return // don't fall through to the error below - } - } - t.Fatalf("no diagnostic is marked as being caused by unknown\n%s", diags.Err().Error()) -} - -func TestContext2Plan_destroy(t *testing.T) { - m := testModule(t, "plan-destroy") - p := testProvider("aws") - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.one").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.two").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"baz"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 2 { - t.Fatal("expected 2 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "aws_instance.one", "aws_instance.two": - if res.Action != plans.Delete { - t.Fatalf("resource %s should be removed", i) - } - - default: - t.Fatal("unknown instance:", i) - } - } -} - -func TestContext2Plan_moduleDestroy(t *testing.T) { - m := testModule(t, "plan-module-destroy") - p := testProvider("aws") - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey)) - child.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 2 { - t.Fatal("expected 2 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "aws_instance.foo", "module.child.aws_instance.foo": - if res.Action != plans.Delete { - t.Fatalf("resource %s should be removed", i) - } - - default: - t.Fatal("unknown instance:", i) - } - } -} - -// GH-1835 -func TestContext2Plan_moduleDestroyCycle(t *testing.T) { - m := testModule(t, "plan-module-destroy-gh-1835") - p := testProvider("aws") - - state := states.NewState() - aModule := state.EnsureModule(addrs.RootModuleInstance.Child("a_module", addrs.NoKey)) - aModule.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.a").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"a"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - bModule := state.EnsureModule(addrs.RootModuleInstance.Child("b_module", addrs.NoKey)) - bModule.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.b").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"b"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 2 { - t.Fatal("expected 2 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "module.a_module.aws_instance.a", "module.b_module.aws_instance.b": - if res.Action != plans.Delete { - t.Fatalf("resource %s should be removed", i) - } - - default: - t.Fatal("unknown instance:", i) - } - } -} - -func TestContext2Plan_moduleDestroyMultivar(t *testing.T) { - m := testModule(t, "plan-module-destroy-multivar") - p := testProvider("aws") - - state := states.NewState() - child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey)) - child.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[0]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar0"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - child.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[1]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar1"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 2 { - t.Fatal("expected 2 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "module.child.aws_instance.foo[0]", "module.child.aws_instance.foo[1]": - if res.Action != plans.Delete { - t.Fatalf("resource %s should be removed", i) - } - - default: - t.Fatal("unknown instance:", i) - } - } -} - -func TestContext2Plan_pathVar(t *testing.T) { - cwd, err := os.Getwd() - if err != nil { - t.Fatalf("err: %s", err) - } - - m := testModule(t, "plan-path-var") - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "cwd": {Type: cty.String, Optional: true}, - "module": {Type: cty.String, Optional: true}, - "root": {Type: cty.String, Optional: true}, - }, - }, - }, - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("err: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 1 { - t.Fatal("expected 1 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "aws_instance.foo": - if res.Action != plans.Create { - t.Fatalf("resource %s should be created", i) - } - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "cwd": cty.StringVal(cwd + "/barpath"), - "module": cty.StringVal(m.Module.SourceDir + "/foopath"), - "root": cty.StringVal(m.Module.SourceDir + "/barpath"), - }), ric.After) - default: - t.Fatal("unknown instance:", i) - } - } -} - -func TestContext2Plan_diffVar(t *testing.T) { - m := testModule(t, "plan-diffvar") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar","num":"2","type":"aws_instance"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 2 { - t.Fatal("expected 2 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "aws_instance.bar": - if res.Action != plans.Create { - t.Fatalf("resource %s should be created", i) - } - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "num": cty.NumberIntVal(3), - "type": cty.UnknownVal(cty.String), - }), ric.After) - case "aws_instance.foo": - if res.Action != plans.Update { - t.Fatalf("resource %s should be updated", i) - } - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.StringVal("bar"), - "num": cty.NumberIntVal(2), - "type": cty.StringVal("aws_instance"), - }), ric.Before) - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.StringVal("bar"), - "num": cty.NumberIntVal(3), - "type": cty.StringVal("aws_instance"), - }), ric.After) - default: - t.Fatal("unknown instance:", i) - } - } -} - -func TestContext2Plan_hook(t *testing.T) { - m := testModule(t, "plan-good") - h := new(MockHook) - p := testProvider("aws") - ctx := testContext2(t, &ContextOpts{ - Hooks: []Hook{h}, - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - _, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - if !h.PreDiffCalled { - t.Fatal("should be called") - } - if !h.PostDiffCalled { - t.Fatal("should be called") - } -} - -func TestContext2Plan_closeProvider(t *testing.T) { - // this fixture only has an aliased provider located in the module, to make - // sure that the provier name contains a path more complex than - // "provider.aws". - m := testModule(t, "plan-close-module-provider") - p := testProvider("aws") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - _, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - if !p.CloseCalled { - t.Fatal("provider not closed") - } -} - -func TestContext2Plan_orphan(t *testing.T) { - m := testModule(t, "plan-orphan") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.baz").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 2 { - t.Fatal("expected 2 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "aws_instance.baz": - if res.Action != plans.Delete { - t.Fatalf("resource %s should be removed", i) - } - if got, want := ric.ActionReason, plans.ResourceInstanceDeleteBecauseNoResourceConfig; got != want { - t.Errorf("wrong action reason\ngot: %s\nwant: %s", got, want) - } - case "aws_instance.foo": - if res.Action != plans.Create { - t.Fatalf("resource %s should be created", i) - } - if got, want := ric.ActionReason, plans.ResourceInstanceChangeNoReason; got != want { - t.Errorf("wrong action reason\ngot: %s\nwant: %s", got, want) - } - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "num": cty.NumberIntVal(2), - "type": cty.UnknownVal(cty.String), - }), ric.After) - default: - t.Fatal("unknown instance:", i) - } - } -} - -// This tests that configurations with UUIDs don't produce errors. -// For shadows, this would produce errors since a UUID changes every time. -func TestContext2Plan_shadowUuid(t *testing.T) { - m := testModule(t, "plan-shadow-uuid") - p := testProvider("aws") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - _, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } -} - -func TestContext2Plan_state(t *testing.T) { - m := testModule(t, "plan-good") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - if len(plan.Changes.Resources) < 2 { - t.Fatalf("bad: %#v", plan.Changes.Resources) - } - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 2 { - t.Fatal("expected 2 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "aws_instance.bar": - if res.Action != plans.Create { - t.Fatalf("resource %s should be created", i) - } - if got, want := ric.ActionReason, plans.ResourceInstanceChangeNoReason; got != want { - t.Errorf("wrong action reason\ngot: %s\nwant: %s", got, want) - } - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("2"), - "type": cty.UnknownVal(cty.String), - }), ric.After) - case "aws_instance.foo": - if res.Action != plans.Update { - t.Fatalf("resource %s should be updated", i) - } - if got, want := ric.ActionReason, plans.ResourceInstanceChangeNoReason; got != want { - t.Errorf("wrong action reason\ngot: %s\nwant: %s", got, want) - } - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.StringVal("bar"), - "num": cty.NullVal(cty.Number), - "type": cty.NullVal(cty.String), - }), ric.Before) - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.StringVal("bar"), - "num": cty.NumberIntVal(2), - "type": cty.UnknownVal(cty.String), - }), ric.After) - default: - t.Fatal("unknown instance:", i) - } - } -} - -func TestContext2Plan_requiresReplace(t *testing.T) { - m := testModule(t, "plan-requires-replace") - p := testProvider("test") - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - Provider: providers.Schema{ - Block: &configschema.Block{}, - }, - ResourceTypes: map[string]providers.Schema{ - "test_thing": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "v": { - Type: cty.String, - Required: true, - }, - }, - }, - }, - }, - } - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse { - return providers.PlanResourceChangeResponse{ - PlannedState: req.ProposedNewState, - RequiresReplace: []cty.Path{ - cty.GetAttrPath("v"), - }, - } - } - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_thing.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"v":"hello"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["test_thing"].Block - ty := schema.ImpliedType() - - if got, want := len(plan.Changes.Resources), 1; got != want { - t.Fatalf("got %d changes; want %d", got, want) - } - - for _, res := range plan.Changes.Resources { - t.Run(res.Addr.String(), func(t *testing.T) { - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "test_thing.foo": - if got, want := ric.Action, plans.DeleteThenCreate; got != want { - t.Errorf("wrong action\ngot: %s\nwant: %s", got, want) - } - if got, want := ric.ActionReason, plans.ResourceInstanceReplaceBecauseCannotUpdate; got != want { - t.Errorf("wrong action reason\ngot: %s\nwant: %s", got, want) - } - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "v": cty.StringVal("goodbye"), - }), ric.After) - default: - t.Fatalf("unexpected resource instance %s", i) - } - }) - } -} - -func TestContext2Plan_taint(t *testing.T) { - m := testModule(t, "plan-taint") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar","num":"2","type":"aws_instance"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectTainted, - AttrsJSON: []byte(`{"id":"baz"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 2 { - t.Fatal("expected 2 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - t.Run(res.Addr.String(), func(t *testing.T) { - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "aws_instance.bar": - if got, want := res.Action, plans.DeleteThenCreate; got != want { - t.Errorf("wrong action\ngot: %s\nwant: %s", got, want) - } - if got, want := res.ActionReason, plans.ResourceInstanceReplaceBecauseTainted; got != want { - t.Errorf("wrong action reason\ngot: %s\nwant: %s", got, want) - } - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("2"), - "type": cty.UnknownVal(cty.String), - }), ric.After) - case "aws_instance.foo": - if got, want := res.Action, plans.NoOp; got != want { - t.Errorf("wrong action\ngot: %s\nwant: %s", got, want) - } - if got, want := res.ActionReason, plans.ResourceInstanceChangeNoReason; got != want { - t.Errorf("wrong action reason\ngot: %s\nwant: %s", got, want) - } - default: - t.Fatal("unknown instance:", i) - } - }) - } -} - -func TestContext2Plan_taintIgnoreChanges(t *testing.T) { - m := testModule(t, "plan-taint-ignore-changes") - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Computed: true}, - "vars": {Type: cty.String, Optional: true}, - "type": {Type: cty.String, Computed: true}, - }, - }, - }, - }) - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectTainted, - AttrsJSON: []byte(`{"id":"foo","vars":"foo","type":"aws_instance"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 1 { - t.Fatal("expected 1 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "aws_instance.foo": - if got, want := res.Action, plans.DeleteThenCreate; got != want { - t.Errorf("wrong action\ngot: %s\nwant: %s", got, want) - } - if got, want := res.ActionReason, plans.ResourceInstanceReplaceBecauseTainted; got != want { - t.Errorf("wrong action reason\ngot: %s\nwant: %s", got, want) - } - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.StringVal("foo"), - "vars": cty.StringVal("foo"), - "type": cty.StringVal("aws_instance"), - }), ric.Before) - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "vars": cty.StringVal("foo"), - "type": cty.UnknownVal(cty.String), - }), ric.After) - default: - t.Fatal("unknown instance:", i) - } - } -} - -// Fails about 50% of the time before the fix for GH-4982, covers the fix. -func TestContext2Plan_taintDestroyInterpolatedCountRace(t *testing.T) { - m := testModule(t, "plan-taint-interpolated-count") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[0]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectTainted, - AttrsJSON: []byte(`{"id":"bar","type":"aws_instance"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[1]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar","type":"aws_instance"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[2]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar","type":"aws_instance"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - for i := 0; i < 100; i++ { - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state.DeepCopy(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 3 { - t.Fatal("expected 3 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "aws_instance.foo[0]": - if got, want := ric.Action, plans.DeleteThenCreate; got != want { - t.Errorf("wrong action\ngot: %s\nwant: %s", got, want) - } - if got, want := ric.ActionReason, plans.ResourceInstanceReplaceBecauseTainted; got != want { - t.Errorf("wrong action reason\ngot: %s\nwant: %s", got, want) - } - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.StringVal("bar"), - "type": cty.StringVal("aws_instance"), - }), ric.Before) - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "type": cty.UnknownVal(cty.String), - }), ric.After) - case "aws_instance.foo[1]", "aws_instance.foo[2]": - if res.Action != plans.NoOp { - t.Fatalf("resource %s should not be changed", i) - } - default: - t.Fatal("unknown instance:", i) - } - } - } -} - -func TestContext2Plan_targeted(t *testing.T) { - m := testModule(t, "plan-targeted") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - Targets: []addrs.Targetable{ - addrs.RootModuleInstance.Resource( - addrs.ManagedResourceMode, "aws_instance", "foo", - ), - }, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 1 { - t.Fatal("expected 1 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "aws_instance.foo": - if res.Action != plans.Create { - t.Fatalf("resource %s should be created", i) - } - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "num": cty.NumberIntVal(2), - "type": cty.UnknownVal(cty.String), - }), ric.After) - default: - t.Fatal("unknown instance:", i) - } - } -} - -// Test that targeting a module properly plans any inputs that depend -// on another module. -func TestContext2Plan_targetedCrossModule(t *testing.T) { - m := testModule(t, "plan-targeted-cross-module") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - Targets: []addrs.Targetable{ - addrs.RootModuleInstance.Child("B", addrs.NoKey), - }, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 2 { - t.Fatal("expected 2 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - if res.Action != plans.Create { - t.Fatalf("resource %s should be created", ric.Addr) - } - switch i := ric.Addr.String(); i { - case "module.A.aws_instance.foo": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.StringVal("bar"), - "type": cty.UnknownVal(cty.String), - }), ric.After) - case "module.B.aws_instance.bar": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "foo": cty.UnknownVal(cty.String), - "type": cty.UnknownVal(cty.String), - }), ric.After) - default: - t.Fatal("unknown instance:", i) - } - } -} - -func TestContext2Plan_targetedModuleWithProvider(t *testing.T) { - m := testModule(t, "plan-targeted-module-with-provider") - p := testProvider("null") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - Provider: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "key": {Type: cty.String, Optional: true}, - }, - }, - ResourceTypes: map[string]*configschema.Block{ - "null_resource": { - Attributes: map[string]*configschema.Attribute{}, - }, - }, - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("null"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - Targets: []addrs.Targetable{ - addrs.RootModuleInstance.Child("child2", addrs.NoKey), - }, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["null_resource"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 1 { - t.Fatal("expected 1 changes, got", len(plan.Changes.Resources)) - } - - res := plan.Changes.Resources[0] - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - if ric.Addr.String() != "module.child2.null_resource.foo" { - t.Fatalf("unexpcetd resource: %s", ric.Addr) - } -} - -func TestContext2Plan_targetedOrphan(t *testing.T) { - m := testModule(t, "plan-targeted-orphan") - p := testProvider("aws") - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.orphan").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"i-789xyz"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.nottargeted").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"i-abc123"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - Targets: []addrs.Targetable{ - addrs.RootModuleInstance.Resource( - addrs.ManagedResourceMode, "aws_instance", "orphan", - ), - }, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 1 { - t.Fatal("expected 1 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "aws_instance.orphan": - if res.Action != plans.Delete { - t.Fatalf("resource %s should be destroyed", ric.Addr) - } - default: - t.Fatal("unknown instance:", i) - } - } -} - -// https://github.com/hashicorp/terraform/issues/2538 -func TestContext2Plan_targetedModuleOrphan(t *testing.T) { - m := testModule(t, "plan-targeted-module-orphan") - p := testProvider("aws") - - state := states.NewState() - child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey)) - child.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.orphan").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"i-789xyz"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - child.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.nottargeted").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"i-abc123"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.DestroyMode, - Targets: []addrs.Targetable{ - addrs.RootModuleInstance.Child("child", addrs.NoKey).Resource( - addrs.ManagedResourceMode, "aws_instance", "orphan", - ), - }, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 1 { - t.Fatal("expected 1 changes, got", len(plan.Changes.Resources)) - } - - res := plan.Changes.Resources[0] - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - if ric.Addr.String() != "module.child.aws_instance.orphan" { - t.Fatalf("unexpected resource :%s", ric.Addr) - } - if res.Action != plans.Delete { - t.Fatalf("resource %s should be deleted", ric.Addr) - } -} - -func TestContext2Plan_targetedModuleUntargetedVariable(t *testing.T) { - m := testModule(t, "plan-targeted-module-untargeted-variable") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Targets: []addrs.Targetable{ - addrs.RootModuleInstance.Resource( - addrs.ManagedResourceMode, "aws_instance", "blue", - ), - addrs.RootModuleInstance.Child("blue_mod", addrs.NoKey), - }, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 2 { - t.Fatal("expected 2 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - if res.Action != plans.Create { - t.Fatalf("resource %s should be created", ric.Addr) - } - switch i := ric.Addr.String(); i { - case "aws_instance.blue": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "type": cty.UnknownVal(cty.String), - }), ric.After) - case "module.blue_mod.aws_instance.mod": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "value": cty.UnknownVal(cty.String), - "type": cty.UnknownVal(cty.String), - }), ric.After) - default: - t.Fatal("unknown instance:", i) - } - } -} - -// ensure that outputs missing references due to targetting are removed from -// the graph. -func TestContext2Plan_outputContainsTargetedResource(t *testing.T) { - m := testModule(t, "plan-untargeted-resource-output") - p := testProvider("aws") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - _, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Targets: []addrs.Targetable{ - addrs.RootModuleInstance.Child("mod", addrs.NoKey).Resource( - addrs.ManagedResourceMode, "aws_instance", "a", - ), - }, - }) - if diags.HasErrors() { - t.Fatalf("err: %s", diags) - } - if len(diags) != 1 { - t.Fatalf("got %d diagnostics; want 1", diags) - } - if got, want := diags[0].Severity(), tfdiags.Warning; got != want { - t.Errorf("wrong diagnostic severity %#v; want %#v", got, want) - } - if got, want := diags[0].Description().Summary, "Resource targeting is in effect"; got != want { - t.Errorf("wrong diagnostic summary %#v; want %#v", got, want) - } -} - -// https://github.com/hashicorp/terraform/issues/4515 -func TestContext2Plan_targetedOverTen(t *testing.T) { - m := testModule(t, "plan-targeted-over-ten") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - for i := 0; i < 13; i++ { - key := fmt.Sprintf("aws_instance.foo[%d]", i) - id := fmt.Sprintf("i-abc%d", i) - attrs := fmt.Sprintf(`{"id":"%s","type":"aws_instance"}`, id) - - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr(key).Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(attrs), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Targets: []addrs.Targetable{ - addrs.RootModuleInstance.ResourceInstance( - addrs.ManagedResourceMode, "aws_instance", "foo", addrs.IntKey(1), - ), - }, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - for _, res := range plan.Changes.Resources { - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - if res.Action != plans.NoOp { - t.Fatalf("unexpected action %s for %s", res.Action, ric.Addr) - } - } -} - -func TestContext2Plan_provider(t *testing.T) { - m := testModule(t, "plan-provider") - p := testProvider("aws") - - var value interface{} - p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) { - value = req.Config.GetAttr("foo").AsString() - return - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - opts := &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "foo": &InputValue{ - Value: cty.StringVal("bar"), - SourceType: ValueFromCaller, - }, - }, - } - - if _, err := ctx.Plan(m, states.NewState(), opts); err != nil { - t.Fatalf("err: %s", err) - } - - if value != "bar" { - t.Fatalf("bad: %#v", value) - } -} - -func TestContext2Plan_varListErr(t *testing.T) { - m := testModule(t, "plan-var-list-err") - p := testProvider("aws") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - _, err := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - - if err == nil { - t.Fatal("should error") - } -} - -func TestContext2Plan_ignoreChanges(t *testing.T) { - m := testModule(t, "plan-ignore-changes") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar","ami":"ami-abcd1234","type":"aws_instance"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "foo": &InputValue{ - Value: cty.StringVal("ami-1234abcd"), - SourceType: ValueFromCaller, - }, - }, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 1 { - t.Fatal("expected 1 changes, got", len(plan.Changes.Resources)) - } - - res := plan.Changes.Resources[0] - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - if ric.Addr.String() != "aws_instance.foo" { - t.Fatalf("unexpected resource: %s", ric.Addr) - } - - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.StringVal("bar"), - "ami": cty.StringVal("ami-abcd1234"), - "type": cty.StringVal("aws_instance"), - }), ric.After) -} - -func TestContext2Plan_ignoreChangesWildcard(t *testing.T) { - m := testModule(t, "plan-ignore-changes-wildcard") - p := testProvider("aws") - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { - // computed attributes should not be set in config - id := req.Config.GetAttr("id") - if !id.IsNull() { - t.Error("computed id set in plan config") - } - - foo := req.Config.GetAttr("foo") - if foo.IsNull() { - t.Error(`missing "foo" during plan, was set to "bar" in state and config`) - } - - return testDiffFn(req) - } - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar","ami":"ami-abcd1234","instance":"t2.micro","type":"aws_instance","foo":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "foo": &InputValue{ - Value: cty.StringVal("ami-1234abcd"), - SourceType: ValueFromCaller, - }, - "bar": &InputValue{ - Value: cty.StringVal("t2.small"), - SourceType: ValueFromCaller, - }, - }, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - for _, res := range plan.Changes.Resources { - if res.Action != plans.NoOp { - t.Fatalf("unexpected resource diffs in root module: %s", spew.Sdump(plan.Changes.Resources)) - } - } -} - -func TestContext2Plan_ignoreChangesInMap(t *testing.T) { - p := testProvider("test") - - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test_ignore_changes_map": { - Attributes: map[string]*configschema.Attribute{ - "tags": {Type: cty.Map(cty.String), Optional: true}, - }, - }, - }, - }) - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse { - return providers.PlanResourceChangeResponse{ - PlannedState: req.ProposedNewState, - } - } - - s := states.BuildState(func(ss *states.SyncState) { - ss.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_ignore_changes_map", - Name: "foo", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo","tags":{"ignored":"from state","other":"from state"},"type":"aws_instance"}`), - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("test"), - Module: addrs.RootModule, - }, - ) - }) - m := testModule(t, "plan-ignore-changes-in-map") - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, s, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["test_ignore_changes_map"].Block - ty := schema.ImpliedType() - - if got, want := len(plan.Changes.Resources), 1; got != want { - t.Fatalf("wrong number of changes %d; want %d", got, want) - } - - res := plan.Changes.Resources[0] - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - if res.Action != plans.Update { - t.Fatalf("resource %s should be updated, got %s", ric.Addr, res.Action) - } - - if got, want := ric.Addr.String(), "test_ignore_changes_map.foo"; got != want { - t.Fatalf("unexpected resource address %s; want %s", got, want) - } - - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "tags": cty.MapVal(map[string]cty.Value{ - "ignored": cty.StringVal("from state"), - "other": cty.StringVal("from config"), - }), - }), ric.After) -} - -func TestContext2Plan_ignoreChangesSensitive(t *testing.T) { - m := testModule(t, "plan-ignore-changes-sensitive") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar","ami":"ami-abcd1234","type":"aws_instance"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "foo": &InputValue{ - Value: cty.StringVal("ami-1234abcd"), - SourceType: ValueFromCaller, - }, - }, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 1 { - t.Fatal("expected 1 changes, got", len(plan.Changes.Resources)) - } - - res := plan.Changes.Resources[0] - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - if ric.Addr.String() != "aws_instance.foo" { - t.Fatalf("unexpected resource: %s", ric.Addr) - } - - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.StringVal("bar"), - "ami": cty.StringVal("ami-abcd1234"), - "type": cty.StringVal("aws_instance"), - }), ric.After) -} - -func TestContext2Plan_moduleMapLiteral(t *testing.T) { - m := testModule(t, "plan-module-map-literal") - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "meta": {Type: cty.Map(cty.String), Optional: true}, - "tags": {Type: cty.Map(cty.String), Optional: true}, - }, - }, - }, - }) - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { - s := req.ProposedNewState.AsValueMap() - m := s["tags"].AsValueMap() - - if m["foo"].AsString() != "bar" { - t.Fatalf("Bad value in tags attr: %#v", m) - } - - meta := s["meta"].AsValueMap() - if len(meta) != 0 { - t.Fatalf("Meta attr not empty: %#v", meta) - } - return testDiffFn(req) - } - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - _, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } -} - -func TestContext2Plan_computedValueInMap(t *testing.T) { - m := testModule(t, "plan-computed-value-in-map") - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "looked_up": {Type: cty.String, Optional: true}, - }, - }, - "aws_computed_source": { - Attributes: map[string]*configschema.Attribute{ - "computed_read_only": {Type: cty.String, Computed: true}, - }, - }, - }, - }) - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { - resp = testDiffFn(req) - - if req.TypeName != "aws_computed_source" { - return - } - - planned := resp.PlannedState.AsValueMap() - planned["computed_read_only"] = cty.UnknownVal(cty.String) - resp.PlannedState = cty.ObjectVal(planned) - return resp - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - if len(plan.Changes.Resources) != 2 { - t.Fatal("expected 2 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - schema := p.GetProviderSchemaResponse.ResourceTypes[res.Addr.Resource.Resource.Type].Block - - ric, err := res.Decode(schema.ImpliedType()) - if err != nil { - t.Fatal(err) - } - - if res.Action != plans.Create { - t.Fatalf("resource %s should be created", ric.Addr) - } - - switch i := ric.Addr.String(); i { - case "aws_computed_source.intermediates": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "computed_read_only": cty.UnknownVal(cty.String), - }), ric.After) - case "module.test_mod.aws_instance.inner2": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "looked_up": cty.UnknownVal(cty.String), - }), ric.After) - default: - t.Fatal("unknown instance:", i) - } - } -} - -func TestContext2Plan_moduleVariableFromSplat(t *testing.T) { - m := testModule(t, "plan-module-variable-from-splat") - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "thing": {Type: cty.String, Optional: true}, - }, - }, - }, - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - if len(plan.Changes.Resources) != 4 { - t.Fatal("expected 4 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - schema := p.GetProviderSchemaResponse.ResourceTypes[res.Addr.Resource.Resource.Type].Block - - ric, err := res.Decode(schema.ImpliedType()) - if err != nil { - t.Fatal(err) - } - - if res.Action != plans.Create { - t.Fatalf("resource %s should be created", ric.Addr) - } - - switch i := ric.Addr.String(); i { - case "module.mod1.aws_instance.test[0]", - "module.mod1.aws_instance.test[1]", - "module.mod2.aws_instance.test[0]", - "module.mod2.aws_instance.test[1]": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "thing": cty.StringVal("doesnt"), - }), ric.After) - default: - t.Fatal("unknown instance:", i) - } - } -} - -func TestContext2Plan_createBeforeDestroy_depends_datasource(t *testing.T) { - m := testModule(t, "plan-cbd-depends-datasource") - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "num": {Type: cty.String, Optional: true}, - "computed": {Type: cty.String, Optional: true, Computed: true}, - }, - }, - }, - DataSources: map[string]*configschema.Block{ - "aws_vpc": { - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Computed: true}, - "foo": {Type: cty.Number, Optional: true}, - }, - }, - }, - }) - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse { - computedVal := req.ProposedNewState.GetAttr("computed") - if computedVal.IsNull() { - computedVal = cty.UnknownVal(cty.String) - } - return providers.PlanResourceChangeResponse{ - PlannedState: cty.ObjectVal(map[string]cty.Value{ - "num": req.ProposedNewState.GetAttr("num"), - "computed": computedVal, - }), - } - } - p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse { - cfg := req.Config.AsValueMap() - cfg["id"] = cty.StringVal("data_id") - return providers.ReadDataSourceResponse{ - State: cty.ObjectVal(cfg), - } - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - seenAddrs := make(map[string]struct{}) - for _, res := range plan.Changes.Resources { - var schema *configschema.Block - switch res.Addr.Resource.Resource.Mode { - case addrs.DataResourceMode: - schema = p.GetProviderSchemaResponse.DataSources[res.Addr.Resource.Resource.Type].Block - case addrs.ManagedResourceMode: - schema = p.GetProviderSchemaResponse.ResourceTypes[res.Addr.Resource.Resource.Type].Block - } - - ric, err := res.Decode(schema.ImpliedType()) - if err != nil { - t.Fatal(err) - } - - seenAddrs[ric.Addr.String()] = struct{}{} - - t.Run(ric.Addr.String(), func(t *testing.T) { - switch i := ric.Addr.String(); i { - case "aws_instance.foo[0]": - if res.Action != plans.Create { - t.Fatalf("resource %s should be created, got %s", ric.Addr, ric.Action) - } - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "num": cty.StringVal("2"), - "computed": cty.StringVal("data_id"), - }), ric.After) - case "aws_instance.foo[1]": - if res.Action != plans.Create { - t.Fatalf("resource %s should be created, got %s", ric.Addr, ric.Action) - } - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "num": cty.StringVal("2"), - "computed": cty.StringVal("data_id"), - }), ric.After) - default: - t.Fatal("unknown instance:", i) - } - }) - } - - wantAddrs := map[string]struct{}{ - "aws_instance.foo[0]": {}, - "aws_instance.foo[1]": {}, - } - if !cmp.Equal(seenAddrs, wantAddrs) { - t.Errorf("incorrect addresses in changeset:\n%s", cmp.Diff(wantAddrs, seenAddrs)) - } -} - -// interpolated lists need to be stored in the original order. -func TestContext2Plan_listOrder(t *testing.T) { - m := testModule(t, "plan-list-order") - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.List(cty.String), Optional: true}, - }, - }, - }, - }) - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - changes := plan.Changes - rDiffA := changes.ResourceInstance(addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "a", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)) - rDiffB := changes.ResourceInstance(addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "b", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)) - - if !cmp.Equal(rDiffA.After, rDiffB.After, valueComparer) { - t.Fatal(cmp.Diff(rDiffA.After, rDiffB.After, valueComparer)) - } -} - -// Make sure ignore-changes doesn't interfere with set/list/map diffs. -// If a resource was being replaced by a RequiresNew attribute that gets -// ignored, we need to filter the diff properly to properly update rather than -// replace. -func TestContext2Plan_ignoreChangesWithFlatmaps(t *testing.T) { - m := testModule(t, "plan-ignore-changes-with-flatmaps") - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "user_data": {Type: cty.String, Optional: true}, - "require_new": {Type: cty.String, Optional: true}, - - // This test predates the 0.12 work to integrate cty and - // HCL, and so it was ported as-is where its expected - // test output was clearly expecting a list of maps here - // even though it is named "set". - "set": {Type: cty.List(cty.Map(cty.String)), Optional: true}, - "lst": {Type: cty.List(cty.String), Optional: true}, - }, - }, - }, - }) - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{ - "user_data":"x","require_new":"", - "set":[{"a":"1"}], - "lst":["j"] - }`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - if len(plan.Changes.Resources) != 1 { - t.Fatal("expected 1 changes, got", len(plan.Changes.Resources)) - } - - res := plan.Changes.Resources[0] - schema := p.GetProviderSchemaResponse.ResourceTypes[res.Addr.Resource.Resource.Type].Block - - ric, err := res.Decode(schema.ImpliedType()) - if err != nil { - t.Fatal(err) - } - - if res.Action != plans.Update { - t.Fatalf("resource %s should be updated, got %s", ric.Addr, ric.Action) - } - - if ric.Addr.String() != "aws_instance.foo" { - t.Fatalf("unknown resource: %s", ric.Addr) - } - - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "lst": cty.ListVal([]cty.Value{ - cty.StringVal("j"), - cty.StringVal("k"), - }), - "require_new": cty.StringVal(""), - "user_data": cty.StringVal("x"), - "set": cty.ListVal([]cty.Value{cty.MapVal(map[string]cty.Value{ - "a": cty.StringVal("1"), - "b": cty.StringVal("2"), - })}), - }), ric.After) -} - -// TestContext2Plan_resourceNestedCount ensures resource sets that depend on -// the count of another resource set (ie: count of a data source that depends -// on another data source's instance count - data.x.foo.*.id) get properly -// normalized to the indexes they should be. This case comes up when there is -// an existing state (after an initial apply). -func TestContext2Plan_resourceNestedCount(t *testing.T) { - m := testModule(t, "nested-resource-count-plan") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse { - return providers.ReadResourceResponse{ - NewState: req.PriorState, - } - } - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[0]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo0","type":"aws_instance"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[1]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo1","type":"aws_instance"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar[0]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar0","type":"aws_instance"}`), - Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.foo")}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar[1]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar1","type":"aws_instance"}`), - Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.foo")}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.baz[0]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"baz0","type":"aws_instance"}`), - Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.bar")}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.baz[1]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"baz1","type":"aws_instance"}`), - Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.bar")}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := ctx.Validate(m) - if diags.HasErrors() { - t.Fatalf("validate errors: %s", diags.Err()) - } - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("plan errors: %s", diags.Err()) - } - - for _, res := range plan.Changes.Resources { - if res.Action != plans.NoOp { - t.Fatalf("resource %s should not change, plan returned %s", res.Addr, res.Action) - } - } -} - -// Higher level test at TestResource_dataSourceListApplyPanic -func TestContext2Plan_computedAttrRefTypeMismatch(t *testing.T) { - m := testModule(t, "plan-computed-attr-ref-type-mismatch") - p := testProvider("aws") - p.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse { - var diags tfdiags.Diagnostics - if req.TypeName == "aws_instance" { - amiVal := req.Config.GetAttr("ami") - if amiVal.Type() != cty.String { - diags = diags.Append(fmt.Errorf("Expected ami to be cty.String, got %#v", amiVal)) - } - } - return providers.ValidateResourceConfigResponse{ - Diagnostics: diags, - } - } - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - if req.TypeName != "aws_ami_list" { - t.Fatalf("Reached apply for unexpected resource type! %s", req.TypeName) - } - // Pretend like we make a thing and the computed list "ids" is populated - s := req.PlannedState.AsValueMap() - s["id"] = cty.StringVal("someid") - s["ids"] = cty.ListVal([]cty.Value{ - cty.StringVal("ami-abc123"), - cty.StringVal("ami-bcd345"), - }) - - resp.NewState = cty.ObjectVal(s) - return - } - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - _, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if !diags.HasErrors() { - t.Fatalf("Succeeded; want type mismatch error for 'ami' argument") - } - - expected := `Inappropriate value for attribute "ami"` - if errStr := diags.Err().Error(); !strings.Contains(errStr, expected) { - t.Fatalf("expected:\n\n%s\n\nto contain:\n\n%s", errStr, expected) - } -} - -func TestContext2Plan_selfRef(t *testing.T) { - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - }) - - m := testModule(t, "plan-self-ref") - c := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := c.Validate(m) - if diags.HasErrors() { - t.Fatalf("unexpected validation failure: %s", diags.Err()) - } - - _, diags = c.Plan(m, states.NewState(), DefaultPlanOpts) - if !diags.HasErrors() { - t.Fatalf("plan succeeded; want error") - } - - gotErrStr := diags.Err().Error() - wantErrStr := "Self-referential block" - if !strings.Contains(gotErrStr, wantErrStr) { - t.Fatalf("missing expected error\ngot: %s\n\nwant: error containing %q", gotErrStr, wantErrStr) - } -} - -func TestContext2Plan_selfRefMulti(t *testing.T) { - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - }) - - m := testModule(t, "plan-self-ref-multi") - c := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := c.Validate(m) - if diags.HasErrors() { - t.Fatalf("unexpected validation failure: %s", diags.Err()) - } - - _, diags = c.Plan(m, states.NewState(), DefaultPlanOpts) - if !diags.HasErrors() { - t.Fatalf("plan succeeded; want error") - } - - gotErrStr := diags.Err().Error() - wantErrStr := "Self-referential block" - if !strings.Contains(gotErrStr, wantErrStr) { - t.Fatalf("missing expected error\ngot: %s\n\nwant: error containing %q", gotErrStr, wantErrStr) - } -} - -func TestContext2Plan_selfRefMultiAll(t *testing.T) { - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.List(cty.String), Optional: true}, - }, - }, - }, - }) - - m := testModule(t, "plan-self-ref-multi-all") - c := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := c.Validate(m) - if diags.HasErrors() { - t.Fatalf("unexpected validation failure: %s", diags.Err()) - } - - _, diags = c.Plan(m, states.NewState(), DefaultPlanOpts) - if !diags.HasErrors() { - t.Fatalf("plan succeeded; want error") - } - - gotErrStr := diags.Err().Error() - - // The graph is checked for cycles before we can walk it, so we don't - // encounter the self-reference check. - //wantErrStr := "Self-referential block" - wantErrStr := "Cycle" - if !strings.Contains(gotErrStr, wantErrStr) { - t.Fatalf("missing expected error\ngot: %s\n\nwant: error containing %q", gotErrStr, wantErrStr) - } -} - -func TestContext2Plan_invalidOutput(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -data "aws_data_source" "name" {} - -output "out" { - value = data.aws_data_source.name.missing -}`, - }) - - p := testProvider("aws") - p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{ - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("data_id"), - "foo": cty.StringVal("foo"), - }), - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - _, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if !diags.HasErrors() { - // Should get this error: - // Unsupported attribute: This object does not have an attribute named "missing" - t.Fatal("succeeded; want errors") - } - - gotErrStr := diags.Err().Error() - wantErrStr := "Unsupported attribute" - if !strings.Contains(gotErrStr, wantErrStr) { - t.Fatalf("missing expected error\ngot: %s\n\nwant: error containing %q", gotErrStr, wantErrStr) - } -} - -func TestContext2Plan_invalidModuleOutput(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "child/main.tf": ` -data "aws_data_source" "name" {} - -output "out" { - value = "${data.aws_data_source.name.missing}" -}`, - "main.tf": ` -module "child" { - source = "./child" -} - -resource "aws_instance" "foo" { - foo = "${module.child.out}" -}`, - }) - - p := testProvider("aws") - p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{ - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("data_id"), - "foo": cty.StringVal("foo"), - }), - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - _, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if !diags.HasErrors() { - // Should get this error: - // Unsupported attribute: This object does not have an attribute named "missing" - t.Fatal("succeeded; want errors") - } - - gotErrStr := diags.Err().Error() - wantErrStr := "Unsupported attribute" - if !strings.Contains(gotErrStr, wantErrStr) { - t.Fatalf("missing expected error\ngot: %s\n\nwant: error containing %q", gotErrStr, wantErrStr) - } -} - -func TestContext2Plan_variableValidation(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -variable "x" { - default = "bar" -} - -resource "aws_instance" "foo" { - foo = var.x -}`, - }) - - p := testProvider("aws") - p.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) (resp providers.ValidateResourceConfigResponse) { - foo := req.Config.GetAttr("foo").AsString() - if foo == "bar" { - resp.Diagnostics = resp.Diagnostics.Append(errors.New("foo cannot be bar")) - } - return - } - - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { - resp.PlannedState = req.ProposedNewState - return - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - _, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if !diags.HasErrors() { - // Should get this error: - // Unsupported attribute: This object does not have an attribute named "missing" - t.Fatal("succeeded; want errors") - } -} - -func TestContext2Plan_variableSensitivity(t *testing.T) { - m := testModule(t, "plan-variable-sensitivity") - - p := testProvider("aws") - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { - resp.PlannedState = req.ProposedNewState - return - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 1 { - t.Fatal("expected 1 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - if res.Action != plans.Create { - t.Fatalf("expected resource creation, got %s", res.Action) - } - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "aws_instance.foo": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "foo": cty.StringVal("foo").Mark(marks.Sensitive), - }), ric.After) - if len(res.ChangeSrc.BeforeValMarks) != 0 { - t.Errorf("unexpected BeforeValMarks: %#v", res.ChangeSrc.BeforeValMarks) - } - if len(res.ChangeSrc.AfterValMarks) != 1 { - t.Errorf("unexpected AfterValMarks: %#v", res.ChangeSrc.AfterValMarks) - continue - } - pvm := res.ChangeSrc.AfterValMarks[0] - if got, want := pvm.Path, cty.GetAttrPath("foo"); !got.Equals(want) { - t.Errorf("unexpected path for mark\n got: %#v\nwant: %#v", got, want) - } - if got, want := pvm.Marks, cty.NewValueMarks(marks.Sensitive); !got.Equal(want) { - t.Errorf("unexpected value for mark\n got: %#v\nwant: %#v", got, want) - } - default: - t.Fatal("unknown instance:", i) - } - } -} - -func TestContext2Plan_variableSensitivityModule(t *testing.T) { - m := testModule(t, "plan-variable-sensitivity-module") - - p := testProvider("aws") - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { - resp.PlannedState = req.ProposedNewState - return - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - SetVariables: InputValues{ - "sensitive_var": {Value: cty.NilVal}, - "another_var": &InputValue{ - Value: cty.StringVal("boop"), - SourceType: ValueFromCaller, - }, - }, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 1 { - t.Fatal("expected 1 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - if res.Action != plans.Create { - t.Fatalf("expected resource creation, got %s", res.Action) - } - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "module.child.aws_instance.foo": - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "foo": cty.StringVal("foo").Mark(marks.Sensitive), - "value": cty.StringVal("boop").Mark(marks.Sensitive), - }), ric.After) - if len(res.ChangeSrc.BeforeValMarks) != 0 { - t.Errorf("unexpected BeforeValMarks: %#v", res.ChangeSrc.BeforeValMarks) - } - if len(res.ChangeSrc.AfterValMarks) != 2 { - t.Errorf("expected AfterValMarks to contain two elements: %#v", res.ChangeSrc.AfterValMarks) - continue - } - // validate that the after marks have "foo" and "value" - contains := func(pvmSlice []cty.PathValueMarks, stepName string) bool { - for _, pvm := range pvmSlice { - if pvm.Path.Equals(cty.GetAttrPath(stepName)) { - if pvm.Marks.Equal(cty.NewValueMarks(marks.Sensitive)) { - return true - } - } - } - return false - } - if !contains(res.ChangeSrc.AfterValMarks, "foo") { - t.Error("unexpected AfterValMarks to contain \"foo\" with sensitive mark") - } - if !contains(res.ChangeSrc.AfterValMarks, "value") { - t.Error("unexpected AfterValMarks to contain \"value\" with sensitive mark") - } - default: - t.Fatal("unknown instance:", i) - } - } -} - -func checkVals(t *testing.T, expected, got cty.Value) { - t.Helper() - // The GoStringer format seems to result in the closest thing to a useful - // diff for values with marks. - // TODO: if we want to continue using cmp.Diff on cty.Values, we should - // make a transformer that creates a more comparable structure. - valueTrans := cmp.Transformer("gostring", func(v cty.Value) string { - return fmt.Sprintf("%#v\n", v) - }) - if !cmp.Equal(expected, got, valueComparer, typeComparer, equateEmpty) { - t.Fatal(cmp.Diff(expected, got, valueTrans, equateEmpty)) - } -} - -func objectVal(t *testing.T, schema *configschema.Block, m map[string]cty.Value) cty.Value { - t.Helper() - v, err := schema.CoerceValue( - cty.ObjectVal(m), - ) - if err != nil { - t.Fatal(err) - } - return v -} - -func TestContext2Plan_requiredModuleOutput(t *testing.T) { - m := testModule(t, "plan-required-output") - p := testProvider("test") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test_resource": { - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Computed: true}, - "required": {Type: cty.String, Required: true}, - }, - }, - }, - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["test_resource"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 2 { - t.Fatal("expected 2 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - t.Run(fmt.Sprintf("%s %s", res.Action, res.Addr), func(t *testing.T) { - if res.Action != plans.Create { - t.Fatalf("expected resource creation, got %s", res.Action) - } - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - var expected cty.Value - switch i := ric.Addr.String(); i { - case "test_resource.root": - expected = objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "required": cty.UnknownVal(cty.String), - }) - case "module.mod.test_resource.for_output": - expected = objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "required": cty.StringVal("val"), - }) - default: - t.Fatal("unknown instance:", i) - } - - checkVals(t, expected, ric.After) - }) - } -} - -func TestContext2Plan_requiredModuleObject(t *testing.T) { - m := testModule(t, "plan-required-whole-mod") - p := testProvider("test") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test_resource": { - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Computed: true}, - "required": {Type: cty.String, Required: true}, - }, - }, - }, - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - - schema := p.GetProviderSchemaResponse.ResourceTypes["test_resource"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 2 { - t.Fatal("expected 2 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - t.Run(fmt.Sprintf("%s %s", res.Action, res.Addr), func(t *testing.T) { - if res.Action != plans.Create { - t.Fatalf("expected resource creation, got %s", res.Action) - } - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - var expected cty.Value - switch i := ric.Addr.String(); i { - case "test_resource.root": - expected = objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "required": cty.UnknownVal(cty.String), - }) - case "module.mod.test_resource.for_output": - expected = objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "required": cty.StringVal("val"), - }) - default: - t.Fatal("unknown instance:", i) - } - - checkVals(t, expected, ric.After) - }) - } -} - -func TestContext2Plan_expandOrphan(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -module "mod" { - count = 1 - source = "./mod" -} -`, - "mod/main.tf": ` -resource "aws_instance" "foo" { -} -`, - }) - - state := states.NewState() - state.EnsureModule(addrs.RootModuleInstance.Child("mod", addrs.IntKey(0))).SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"child","type":"aws_instance"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - state.EnsureModule(addrs.RootModuleInstance.Child("mod", addrs.IntKey(1))).SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"child","type":"aws_instance"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - - expected := map[string]plans.Action{ - `module.mod[1].aws_instance.foo`: plans.Delete, - `module.mod[0].aws_instance.foo`: plans.NoOp, - } - - for _, res := range plan.Changes.Resources { - want := expected[res.Addr.String()] - if res.Action != want { - t.Fatalf("expected %s action, got: %q %s", want, res.Addr, res.Action) - } - delete(expected, res.Addr.String()) - } - - for res, action := range expected { - t.Errorf("missing %s change for %s", action, res) - } -} - -func TestContext2Plan_indexInVar(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -module "a" { - count = 1 - source = "./mod" - in = "test" -} - -module "b" { - count = 1 - source = "./mod" - in = length(module.a) -} -`, - "mod/main.tf": ` -resource "aws_instance" "foo" { - foo = var.in -} - -variable "in" { -} - -output"out" { - value = aws_instance.foo.id -} -`, - }) - - p := testProvider("aws") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - _, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } -} - -func TestContext2Plan_targetExpandedAddress(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -module "mod" { - count = 3 - source = "./mod" -} -`, - "mod/main.tf": ` -resource "aws_instance" "foo" { - count = 2 -} -`, - }) - - p := testProvider("aws") - - targets := []addrs.Targetable{} - target, diags := addrs.ParseTargetStr("module.mod[1].aws_instance.foo[0]") - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - targets = append(targets, target.Subject) - - target, diags = addrs.ParseTargetStr("module.mod[2]") - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - targets = append(targets, target.Subject) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - Targets: targets, - }) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - - expected := map[string]plans.Action{ - // the single targeted mod[1] instances - `module.mod[1].aws_instance.foo[0]`: plans.Create, - // the whole mode[2] - `module.mod[2].aws_instance.foo[0]`: plans.Create, - `module.mod[2].aws_instance.foo[1]`: plans.Create, - } - - for _, res := range plan.Changes.Resources { - want := expected[res.Addr.String()] - if res.Action != want { - t.Fatalf("expected %s action, got: %q %s", want, res.Addr, res.Action) - } - delete(expected, res.Addr.String()) - } - - for res, action := range expected { - t.Errorf("missing %s change for %s", action, res) - } -} - -func TestContext2Plan_targetResourceInModuleInstance(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -module "mod" { - count = 3 - source = "./mod" -} -`, - "mod/main.tf": ` -resource "aws_instance" "foo" { -} -`, - }) - - p := testProvider("aws") - - target, diags := addrs.ParseTargetStr("module.mod[1].aws_instance.foo") - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - - targets := []addrs.Targetable{target.Subject} - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - Targets: targets, - }) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - - expected := map[string]plans.Action{ - // the single targeted mod[1] instance - `module.mod[1].aws_instance.foo`: plans.Create, - } - - for _, res := range plan.Changes.Resources { - want := expected[res.Addr.String()] - if res.Action != want { - t.Fatalf("expected %s action, got: %q %s", want, res.Addr, res.Action) - } - delete(expected, res.Addr.String()) - } - - for res, action := range expected { - t.Errorf("missing %s change for %s", action, res) - } -} - -func TestContext2Plan_moduleRefIndex(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -module "mod" { - for_each = { - a = "thing" - } - in = null - source = "./mod" -} - -module "single" { - source = "./mod" - in = module.mod["a"] -} -`, - "mod/main.tf": ` -variable "in" { -} - -output "out" { - value = "foo" -} - -resource "aws_instance" "foo" { -} -`, - }) - - p := testProvider("aws") - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - _, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } -} - -func TestContext2Plan_noChangeDataPlan(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -data "test_data_source" "foo" {} -`, - }) - - p := new(MockProvider) - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - DataSources: map[string]*configschema.Block{ - "test_data_source": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - "foo": { - Type: cty.String, - Optional: true, - }, - }, - }, - }, - }) - - p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{ - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("data_id"), - "foo": cty.StringVal("foo"), - }), - } - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("data.test_data_source.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"data_id", "foo":"foo"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - - for _, res := range plan.Changes.Resources { - if res.Action != plans.NoOp { - t.Fatalf("expected NoOp, got: %q %s", res.Addr, res.Action) - } - } -} - -// for_each can reference a resource with 0 instances -func TestContext2Plan_scaleInForEach(t *testing.T) { - p := testProvider("test") - - m := testModuleInline(t, map[string]string{ - "main.tf": ` -locals { - m = {} -} - -resource "test_instance" "a" { - for_each = local.m -} - -resource "test_instance" "b" { - for_each = test_instance.a -} -`}) - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_instance.a[0]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"a0"}`), - Dependencies: []addrs.ConfigResource{}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_instance.b").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"b"}`), - Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_instance.a")}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - assertNoErrors(t, diags) - - t.Run("test_instance.a[0]", func(t *testing.T) { - instAddr := mustResourceInstanceAddr("test_instance.a[0]") - change := plan.Changes.ResourceInstance(instAddr) - if change == nil { - t.Fatalf("no planned change for %s", instAddr) - } - if got, want := change.PrevRunAddr, instAddr; !want.Equal(got) { - t.Errorf("wrong previous run address for %s %s; want %s", instAddr, got, want) - } - if got, want := change.Action, plans.Delete; got != want { - t.Errorf("wrong action for %s %s; want %s", instAddr, got, want) - } - if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseWrongRepetition; got != want { - t.Errorf("wrong action reason for %s %s; want %s", instAddr, got, want) - } - }) - t.Run("test_instance.b", func(t *testing.T) { - instAddr := mustResourceInstanceAddr("test_instance.b") - change := plan.Changes.ResourceInstance(instAddr) - if change == nil { - t.Fatalf("no planned change for %s", instAddr) - } - if got, want := change.PrevRunAddr, instAddr; !want.Equal(got) { - t.Errorf("wrong previous run address for %s %s; want %s", instAddr, got, want) - } - if got, want := change.Action, plans.Delete; got != want { - t.Errorf("wrong action for %s %s; want %s", instAddr, got, want) - } - if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseWrongRepetition; got != want { - t.Errorf("wrong action reason for %s %s; want %s", instAddr, got, want) - } - }) -} - -func TestContext2Plan_targetedModuleInstance(t *testing.T) { - m := testModule(t, "plan-targeted") - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ - Mode: plans.NormalMode, - Targets: []addrs.Targetable{ - addrs.RootModuleInstance.Child("mod", addrs.IntKey(0)), - }, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - if len(plan.Changes.Resources) != 1 { - t.Fatal("expected 1 changes, got", len(plan.Changes.Resources)) - } - - for _, res := range plan.Changes.Resources { - ric, err := res.Decode(ty) - if err != nil { - t.Fatal(err) - } - - switch i := ric.Addr.String(); i { - case "module.mod[0].aws_instance.foo": - if res.Action != plans.Create { - t.Fatalf("resource %s should be created", i) - } - checkVals(t, objectVal(t, schema, map[string]cty.Value{ - "id": cty.UnknownVal(cty.String), - "num": cty.NumberIntVal(2), - "type": cty.UnknownVal(cty.String), - }), ric.After) - default: - t.Fatal("unknown instance:", i) - } - } -} - -func TestContext2Plan_dataRefreshedInPlan(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -data "test_data_source" "d" { -} -`}) - - p := testProvider("test") - p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{ - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("this"), - "foo": cty.NullVal(cty.String), - }), - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } - - d := plan.PriorState.ResourceInstance(mustResourceInstanceAddr("data.test_data_source.d")) - if d == nil || d.Current == nil { - t.Fatal("data.test_data_source.d not found in state:", plan.PriorState) - } - - if d.Current.Status != states.ObjectReady { - t.Fatal("expected data.test_data_source.d to be fully read in refreshed state, got status", d.Current.Status) - } -} - -func TestContext2Plan_dataReferencesResourceDirectly(t *testing.T) { - // When a data resource refers to a managed resource _directly_, any - // pending change for the managed resource will cause the data resource - // to be deferred to the apply step. - // See also TestContext2Plan_dataReferencesResourceIndirectly for the - // other case, where the reference is indirect. - - p := testProvider("test") - - p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("data source should not be read")) - return resp - } - - m := testModuleInline(t, map[string]string{ - "main.tf": ` -locals { - x = "value" -} - -resource "test_resource" "a" { - value = local.x -} - -// test_resource.a.value can be resolved during plan, but the reference implies -// that the data source should wait until the resource is created. -data "test_data_source" "d" { - foo = test_resource.a.value -} - -// ensure referencing an indexed instance that has not yet created will also -// delay reading the data source -resource "test_resource" "b" { - count = 2 - value = local.x -} - -data "test_data_source" "e" { - foo = test_resource.b[0].value -} -`}) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - rc := plan.Changes.ResourceInstance(addrs.Resource{ - Mode: addrs.DataResourceMode, - Type: "test_data_source", - Name: "d", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)) - if rc != nil { - if got, want := rc.ActionReason, plans.ResourceInstanceReadBecauseDependencyPending; got != want { - t.Errorf("wrong ActionReason\ngot: %s\nwant: %s", got, want) - } - } else { - t.Error("no change for test_data_source.e") - } -} - -func TestContext2Plan_dataReferencesResourceIndirectly(t *testing.T) { - // When a data resource refers to a managed resource indirectly, pending - // changes for the managed resource _do not_ cause the data resource to - // be deferred to apply. This is a pragmatic special case added for - // backward compatibility with the old situation where we would _always_ - // eagerly read data resources with known configurations, regardless of - // the plans for their dependencies. - // This test creates an indirection through a local value, but the same - // principle would apply for both input variable and output value - // indirection. - // - // See also TestContext2Plan_dataReferencesResourceDirectly for the - // other case, where the reference is direct. - // This special exception doesn't apply for a data resource that has - // custom conditions; see - // TestContext2Plan_dataResourceChecksManagedResourceChange for that - // situation. - - p := testProvider("test") - var applyCount int64 - p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - atomic.AddInt64(&applyCount, 1) - resp.NewState = req.PlannedState - return resp - } - p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) { - if atomic.LoadInt64(&applyCount) == 0 { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("data source read before managed resource apply")) - } else { - resp.State = req.Config - } - return resp - } - - m := testModuleInline(t, map[string]string{ - "main.tf": ` -locals { - x = "value" -} - -resource "test_resource" "a" { - value = local.x -} - -locals { - y = test_resource.a.value -} - -// test_resource.a.value would ideally cause a pending change for -// test_resource.a to defer this to the apply step, but we intentionally don't -// do that when it's indirect (through a local value, here) as a concession -// to backward compatibility. -data "test_data_source" "d" { - foo = local.y -} -`}) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - _, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if !diags.HasErrors() { - t.Fatalf("successful plan; want an error") - } - - if got, want := diags.Err().Error(), "data source read before managed resource apply"; !strings.Contains(got, want) { - t.Errorf("Missing expected error message\ngot: %s\nwant substring: %s", got, want) - } -} - -func TestContext2Plan_skipRefresh(t *testing.T) { - p := testProvider("test") - p.PlanResourceChangeFn = testDiffFn - - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "test_instance" "a" { -} -`}) - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_instance.a").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"a","type":"test_instance"}`), - Dependencies: []addrs.ConfigResource{}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{ - Mode: plans.NormalMode, - SkipRefresh: true, - }) - assertNoErrors(t, diags) - - if p.ReadResourceCalled { - t.Fatal("Resource should not have been refreshed") - } - - for _, c := range plan.Changes.Resources { - if c.Action != plans.NoOp { - t.Fatalf("expected no changes, got %s for %q", c.Action, c.Addr) - } - } -} - -func TestContext2Plan_dataInModuleDependsOn(t *testing.T) { - p := testProvider("test") - - readDataSourceB := false - p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) { - cfg := req.Config.AsValueMap() - foo := cfg["foo"].AsString() - - cfg["id"] = cty.StringVal("ID") - cfg["foo"] = cty.StringVal("new") - - if foo == "b" { - readDataSourceB = true - } - - resp.State = cty.ObjectVal(cfg) - return resp - } - - m := testModuleInline(t, map[string]string{ - "main.tf": ` -module "a" { - source = "./mod_a" -} - -module "b" { - source = "./mod_b" - depends_on = [module.a] -}`, - "mod_a/main.tf": ` -data "test_data_source" "a" { - foo = "a" -}`, - "mod_b/main.tf": ` -data "test_data_source" "b" { - foo = "b" -}`, - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - _, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - assertNoErrors(t, diags) - - // The change to data source a should not prevent data source b from being - // read. - if !readDataSourceB { - t.Fatal("data source b was not read during plan") - } -} - -func TestContext2Plan_rpcDiagnostics(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "test_instance" "a" { -} -`, - }) - - p := testProvider("test") - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse { - resp := testDiffFn(req) - resp.Diagnostics = resp.Diagnostics.Append(tfdiags.SimpleWarning("don't frobble")) - return resp - } - - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test_instance": { - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Computed: true}, - }, - }, - }, - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - _, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatal(diags.Err()) - } - - if len(diags) == 0 { - t.Fatal("expected warnings") - } - - for _, d := range diags { - des := d.Description().Summary - if !strings.Contains(des, "frobble") { - t.Fatalf(`expected frobble, got %q`, des) - } - } -} - -// ignore_changes needs to be re-applied to the planned value for provider -// using the LegacyTypeSystem -func TestContext2Plan_legacyProviderIgnoreChanges(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "test_instance" "a" { - lifecycle { - ignore_changes = [data] - } -} -`, - }) - - p := testProvider("test") - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { - m := req.ProposedNewState.AsValueMap() - // this provider "hashes" the data attribute as bar - m["data"] = cty.StringVal("bar") - - resp.PlannedState = cty.ObjectVal(m) - resp.LegacyTypeSystem = true - return resp - } - - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test_instance": { - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Computed: true}, - "data": {Type: cty.String, Optional: true}, - }, - }, - }, - }) - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_instance.a").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"a","data":"foo"}`), - Dependencies: []addrs.ConfigResource{}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatal(diags.Err()) - } - - for _, c := range plan.Changes.Resources { - if c.Action != plans.NoOp { - t.Fatalf("expected no changes, got %s for %q", c.Action, c.Addr) - } - } -} - -func TestContext2Plan_validateIgnoreAll(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "test_instance" "a" { - lifecycle { - ignore_changes = all - } -} -`, - }) - - p := testProvider("test") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test_instance": { - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Computed: true}, - "data": {Type: cty.String, Optional: true}, - }, - }, - }, - }) - p.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse { - var diags tfdiags.Diagnostics - if req.TypeName == "test_instance" { - if !req.Config.GetAttr("id").IsNull() { - diags = diags.Append(errors.New("id cannot be set in config")) - } - } - return providers.ValidateResourceConfigResponse{ - Diagnostics: diags, - } - } - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_instance.a").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"a","data":"foo"}`), - Dependencies: []addrs.ConfigResource{}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - _, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatal(diags.Err()) - } -} - -func TestContext2Plan_legacyProviderIgnoreAll(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "test_instance" "a" { - lifecycle { - ignore_changes = all - } - data = "foo" -} -`, - }) - - p := testProvider("test") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test_instance": { - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Computed: true}, - "data": {Type: cty.String, Optional: true}, - }, - }, - }, - }) - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { - plan := req.ProposedNewState.AsValueMap() - // Update both the computed id and the configured data. - // Legacy providers expect terraform to be able to ignore these. - - plan["id"] = cty.StringVal("updated") - plan["data"] = cty.StringVal("updated") - resp.PlannedState = cty.ObjectVal(plan) - resp.LegacyTypeSystem = true - return resp - } - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_instance.a").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"orig","data":"orig"}`), - Dependencies: []addrs.ConfigResource{}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatal(diags.Err()) - } - - for _, c := range plan.Changes.Resources { - if c.Action != plans.NoOp { - t.Fatalf("expected NoOp plan, got %s\n", c.Action) - } - } -} - -func TestContext2Plan_dataRemovalNoProvider(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "test_instance" "a" { -} -`, - }) - - p := testProvider("test") - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_instance.a").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"a","data":"foo"}`), - Dependencies: []addrs.ConfigResource{}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - // the provider for this data source is no longer in the config, but that - // should not matter for state removal. - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("data.test_data_source.d").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"d"}`), - Dependencies: []addrs.ConfigResource{}, - }, - mustProviderConfig(`provider["registry.terraform.io/local/test"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - // We still need to be able to locate the provider to decode the - // state, since we do not know during init that this provider is - // only used for an orphaned data source. - addrs.NewProvider("registry.terraform.io", "local", "test"): testProviderFuncFixed(p), - }, - }) - _, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatal(diags.Err()) - } -} - -func TestContext2Plan_noSensitivityChange(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -variable "sensitive_var" { - default = "hello" - sensitive = true -} - -resource "test_resource" "foo" { - value = var.sensitive_var - sensitive_value = var.sensitive_var -}`, - }) - - p := testProvider("test") - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - state := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_resource", - Name: "foo", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo", "value":"hello", "sensitive_value":"hello"}`), - AttrSensitivePaths: []cty.PathValueMarks{ - {Path: cty.Path{cty.GetAttrStep{Name: "value"}}, Marks: cty.NewValueMarks(marks.Sensitive)}, - {Path: cty.Path{cty.GetAttrStep{Name: "sensitive_value"}}, Marks: cty.NewValueMarks(marks.Sensitive)}, - }, - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("test"), - Module: addrs.RootModule, - }, - ) - }) - plan, diags := ctx.Plan(m, state, SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))) - if diags.HasErrors() { - t.Fatal(diags.Err()) - } - - for _, c := range plan.Changes.Resources { - if c.Action != plans.NoOp { - t.Fatalf("expected no changes, got %s for %q", c.Action, c.Addr) - } - } -} - -func TestContext2Plan_variableCustomValidationsSensitive(t *testing.T) { - m := testModule(t, "validate-variable-custom-validations-child-sensitive") - - p := testProvider("test") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - _, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if !diags.HasErrors() { - t.Fatal("succeeded; want errors") - } - if got, want := diags.Err().Error(), `Invalid value for variable: Value must not be "nope".`; !strings.Contains(got, want) { - t.Fatalf("wrong error:\ngot: %s\nwant: message containing %q", got, want) - } -} - -func TestContext2Plan_nullOutputNoOp(t *testing.T) { - // this should always plan a NoOp change for the output - m := testModuleInline(t, map[string]string{ - "main.tf": ` -output "planned" { - value = false ? 1 : null -} -`, - }) - - ctx := testContext2(t, &ContextOpts{}) - state := states.BuildState(func(s *states.SyncState) { - r := s.Module(addrs.RootModuleInstance) - r.SetOutputValue("planned", cty.NullVal(cty.DynamicPseudoType), false) - }) - plan, diags := ctx.Plan(m, state, DefaultPlanOpts) - if diags.HasErrors() { - t.Fatal(diags.Err()) - } - - for _, c := range plan.Changes.Outputs { - if c.Action != plans.NoOp { - t.Fatalf("expected no changes, got %s for %q", c.Action, c.Addr) - } - } -} - -func TestContext2Plan_createOutput(t *testing.T) { - // this should always plan a NoOp change for the output - m := testModuleInline(t, map[string]string{ - "main.tf": ` -output "planned" { - value = 1 -} -`, - }) - - ctx := testContext2(t, &ContextOpts{}) - plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts) - if diags.HasErrors() { - t.Fatal(diags.Err()) - } - - for _, c := range plan.Changes.Outputs { - if c.Action != plans.Create { - t.Fatalf("expected Create change, got %s for %q", c.Action, c.Addr) - } - } -} - -//////////////////////////////////////////////////////////////////////////////// -// NOTE: Due to the size of this file, new tests should be added to -// context_plan2_test.go. -//////////////////////////////////////////////////////////////////////////////// diff --git a/internal/terraform/context_plugins.go b/internal/terraform/context_plugins.go deleted file mode 100644 index 4b3071cf6d84..000000000000 --- a/internal/terraform/context_plugins.go +++ /dev/null @@ -1,209 +0,0 @@ -package terraform - -import ( - "fmt" - "log" - "sync" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/provisioners" -) - -// contextPlugins represents a library of available plugins (providers and -// provisioners) which we assume will all be used with the same -// terraform.Context, and thus it'll be safe to cache certain information -// about the providers for performance reasons. -type contextPlugins struct { - providerFactories map[addrs.Provider]providers.Factory - provisionerFactories map[string]provisioners.Factory - - // We memoize the schemas we've previously loaded in here, to avoid - // repeatedly paying the cost of activating the same plugins to access - // their schemas in various different spots. We use schemas for many - // purposes in Terraform, so there isn't a single choke point where - // it makes sense to preload all of them. - providerSchemas map[addrs.Provider]*ProviderSchema - provisionerSchemas map[string]*configschema.Block - schemasLock sync.Mutex -} - -func newContextPlugins(providerFactories map[addrs.Provider]providers.Factory, provisionerFactories map[string]provisioners.Factory) *contextPlugins { - ret := &contextPlugins{ - providerFactories: providerFactories, - provisionerFactories: provisionerFactories, - } - ret.init() - return ret -} - -func (cp *contextPlugins) init() { - cp.providerSchemas = make(map[addrs.Provider]*ProviderSchema, len(cp.providerFactories)) - cp.provisionerSchemas = make(map[string]*configschema.Block, len(cp.provisionerFactories)) -} - -func (cp *contextPlugins) HasProvider(addr addrs.Provider) bool { - _, ok := cp.providerFactories[addr] - return ok -} - -func (cp *contextPlugins) NewProviderInstance(addr addrs.Provider) (providers.Interface, error) { - f, ok := cp.providerFactories[addr] - if !ok { - return nil, fmt.Errorf("unavailable provider %q", addr.String()) - } - - return f() - -} - -func (cp *contextPlugins) HasProvisioner(typ string) bool { - _, ok := cp.provisionerFactories[typ] - return ok -} - -func (cp *contextPlugins) NewProvisionerInstance(typ string) (provisioners.Interface, error) { - f, ok := cp.provisionerFactories[typ] - if !ok { - return nil, fmt.Errorf("unavailable provisioner %q", typ) - } - - return f() -} - -// ProviderSchema uses a temporary instance of the provider with the given -// address to obtain the full schema for all aspects of that provider. -// -// ProviderSchema memoizes results by unique provider address, so it's fine -// to repeatedly call this method with the same address if various different -// parts of Terraform all need the same schema information. -func (cp *contextPlugins) ProviderSchema(addr addrs.Provider) (*ProviderSchema, error) { - cp.schemasLock.Lock() - defer cp.schemasLock.Unlock() - - if schema, ok := cp.providerSchemas[addr]; ok { - return schema, nil - } - - log.Printf("[TRACE] terraform.contextPlugins: Initializing provider %q to read its schema", addr) - - provider, err := cp.NewProviderInstance(addr) - if err != nil { - return nil, fmt.Errorf("failed to instantiate provider %q to obtain schema: %s", addr, err) - } - defer provider.Close() - - resp := provider.GetProviderSchema() - if resp.Diagnostics.HasErrors() { - return nil, fmt.Errorf("failed to retrieve schema from provider %q: %s", addr, resp.Diagnostics.Err()) - } - - s := &ProviderSchema{ - Provider: resp.Provider.Block, - ResourceTypes: make(map[string]*configschema.Block), - DataSources: make(map[string]*configschema.Block), - - ResourceTypeSchemaVersions: make(map[string]uint64), - } - - if resp.Provider.Version < 0 { - // We're not using the version numbers here yet, but we'll check - // for validity anyway in case we start using them in future. - return nil, fmt.Errorf("provider %s has invalid negative schema version for its configuration blocks,which is a bug in the provider ", addr) - } - - for t, r := range resp.ResourceTypes { - if err := r.Block.InternalValidate(); err != nil { - return nil, fmt.Errorf("provider %s has invalid schema for managed resource type %q, which is a bug in the provider: %q", addr, t, err) - } - s.ResourceTypes[t] = r.Block - s.ResourceTypeSchemaVersions[t] = uint64(r.Version) - if r.Version < 0 { - return nil, fmt.Errorf("provider %s has invalid negative schema version for managed resource type %q, which is a bug in the provider", addr, t) - } - } - - for t, d := range resp.DataSources { - if err := d.Block.InternalValidate(); err != nil { - return nil, fmt.Errorf("provider %s has invalid schema for data resource type %q, which is a bug in the provider: %q", addr, t, err) - } - s.DataSources[t] = d.Block - if d.Version < 0 { - // We're not using the version numbers here yet, but we'll check - // for validity anyway in case we start using them in future. - return nil, fmt.Errorf("provider %s has invalid negative schema version for data resource type %q, which is a bug in the provider", addr, t) - } - } - - if resp.ProviderMeta.Block != nil { - s.ProviderMeta = resp.ProviderMeta.Block - } - - cp.providerSchemas[addr] = s - return s, nil -} - -// ProviderConfigSchema is a helper wrapper around ProviderSchema which first -// reads the full schema of the given provider and then extracts just the -// provider's configuration schema, which defines what's expected in a -// "provider" block in the configuration when configuring this provider. -func (cp *contextPlugins) ProviderConfigSchema(providerAddr addrs.Provider) (*configschema.Block, error) { - providerSchema, err := cp.ProviderSchema(providerAddr) - if err != nil { - return nil, err - } - - return providerSchema.Provider, nil -} - -// ResourceTypeSchema is a helper wrapper around ProviderSchema which first -// reads the schema of the given provider and then tries to find the schema -// for the resource type of the given resource mode in that provider. -// -// ResourceTypeSchema will return an error if the provider schema lookup -// fails, but will return nil if the provider schema lookup succeeds but then -// the provider doesn't have a resource of the requested type. -// -// Managed resource types have versioned schemas, so the second return value -// is the current schema version number for the requested resource. The version -// is irrelevant for other resource modes. -func (cp *contextPlugins) ResourceTypeSchema(providerAddr addrs.Provider, resourceMode addrs.ResourceMode, resourceType string) (*configschema.Block, uint64, error) { - providerSchema, err := cp.ProviderSchema(providerAddr) - if err != nil { - return nil, 0, err - } - - schema, version := providerSchema.SchemaForResourceType(resourceMode, resourceType) - return schema, version, nil -} - -// ProvisionerSchema uses a temporary instance of the provisioner with the -// given type name to obtain the schema for that provisioner's configuration. -// -// ProvisionerSchema memoizes results by provisioner type name, so it's fine -// to repeatedly call this method with the same name if various different -// parts of Terraform all need the same schema information. -func (cp *contextPlugins) ProvisionerSchema(typ string) (*configschema.Block, error) { - cp.schemasLock.Lock() - defer cp.schemasLock.Unlock() - - if schema, ok := cp.provisionerSchemas[typ]; ok { - return schema, nil - } - - log.Printf("[TRACE] terraform.contextPlugins: Initializing provisioner %q to read its schema", typ) - provisioner, err := cp.NewProvisionerInstance(typ) - if err != nil { - return nil, fmt.Errorf("failed to instantiate provisioner %q to obtain schema: %s", typ, err) - } - defer provisioner.Close() - - resp := provisioner.GetSchema() - if resp.Diagnostics.HasErrors() { - return nil, fmt.Errorf("failed to retrieve schema from provisioner %q: %s", typ, resp.Diagnostics.Err()) - } - - cp.provisionerSchemas[typ] = resp.Provisioner - return resp.Provisioner, nil -} diff --git a/internal/terraform/context_plugins_test.go b/internal/terraform/context_plugins_test.go deleted file mode 100644 index 26813ceb0dfa..000000000000 --- a/internal/terraform/context_plugins_test.go +++ /dev/null @@ -1,83 +0,0 @@ -package terraform - -import ( - "github.com/zclconf/go-cty/cty" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/provisioners" -) - -// simpleMockPluginLibrary returns a plugin library pre-configured with -// one provider and one provisioner, both called "test". -// -// The provider is built with simpleMockProvider and the provisioner with -// simpleMockProvisioner, and all schemas used in both are as built by -// function simpleTestSchema. -// -// Each call to this function produces an entirely-separate set of objects, -// so the caller can feel free to modify the returned value to further -// customize the mocks contained within. -func simpleMockPluginLibrary() *contextPlugins { - // We create these out here, rather than in the factory functions below, - // because we want each call to the factory to return the _same_ instance, - // so that test code can customize it before passing this component - // factory into real code under test. - provider := simpleMockProvider() - provisioner := simpleMockProvisioner() - ret := &contextPlugins{ - providerFactories: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): func() (providers.Interface, error) { - return provider, nil - }, - }, - provisionerFactories: map[string]provisioners.Factory{ - "test": func() (provisioners.Interface, error) { - return provisioner, nil - }, - }, - } - ret.init() // prepare the internal cache data structures - return ret -} - -// simpleTestSchema returns a block schema that contains a few optional -// attributes for use in tests. -// -// The returned schema contains the following optional attributes: -// -// - test_string, of type string -// - test_number, of type number -// - test_bool, of type bool -// - test_list, of type list(string) -// - test_map, of type map(string) -// -// Each call to this function produces an entirely new schema instance, so -// callers can feel free to modify it once returned. -func simpleTestSchema() *configschema.Block { - return &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "test_string": { - Type: cty.String, - Optional: true, - }, - "test_number": { - Type: cty.Number, - Optional: true, - }, - "test_bool": { - Type: cty.Bool, - Optional: true, - }, - "test_list": { - Type: cty.List(cty.String), - Optional: true, - }, - "test_map": { - Type: cty.Map(cty.String), - Optional: true, - }, - }, - } -} diff --git a/internal/terraform/context_refresh.go b/internal/terraform/context_refresh.go deleted file mode 100644 index cac5232b0d0f..000000000000 --- a/internal/terraform/context_refresh.go +++ /dev/null @@ -1,37 +0,0 @@ -package terraform - -import ( - "log" - - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -// Refresh is a vestigial operation that is equivalent to call to Plan and -// then taking the prior state of the resulting plan. -// -// We retain this only as a measure of semi-backward-compatibility for -// automation relying on the "terraform refresh" subcommand. The modern way -// to get this effect is to create and then apply a plan in the refresh-only -// mode. -func (c *Context) Refresh(config *configs.Config, prevRunState *states.State, opts *PlanOpts) (*states.State, tfdiags.Diagnostics) { - if opts == nil { - // This fallback is only here for tests, not for real code. - opts = &PlanOpts{ - Mode: plans.NormalMode, - } - } - if opts.Mode != plans.NormalMode { - panic("can only Refresh in the normal planning mode") - } - - log.Printf("[DEBUG] Refresh is really just plan now, so creating a %s plan", opts.Mode) - p, diags := c.Plan(config, prevRunState, opts) - if diags.HasErrors() { - return nil, diags - } - - return p.PriorState, diags -} diff --git a/internal/terraform/context_refresh_test.go b/internal/terraform/context_refresh_test.go deleted file mode 100644 index 9b4f4dab5566..000000000000 --- a/internal/terraform/context_refresh_test.go +++ /dev/null @@ -1,1685 +0,0 @@ -package terraform - -import ( - "reflect" - "sort" - "strings" - "sync" - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/zclconf/go-cty/cty" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/configs/hcl2shim" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" -) - -func TestContext2Refresh(t *testing.T) { - p := testProvider("aws") - m := testModule(t, "refresh-basic") - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.web").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo","foo":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - readState, err := hcl2shim.HCL2ValueFromFlatmap(map[string]string{"id": "foo", "foo": "baz"}, ty) - if err != nil { - t.Fatal(err) - } - - p.ReadResourceResponse = &providers.ReadResourceResponse{ - NewState: readState, - } - - s, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode}) - if diags.HasErrors() { - t.Fatal(diags.Err()) - } - - if !p.ReadResourceCalled { - t.Fatal("ReadResource should be called") - } - - mod := s.RootModule() - fromState, err := mod.Resources["aws_instance.web"].Instances[addrs.NoKey].Current.Decode(ty) - if err != nil { - t.Fatal(err) - } - - newState, err := schema.CoerceValue(fromState.Value) - if err != nil { - t.Fatal(err) - } - - if !cmp.Equal(readState, newState, valueComparer) { - t.Fatal(cmp.Diff(readState, newState, valueComparer, equateEmpty)) - } -} - -func TestContext2Refresh_dynamicAttr(t *testing.T) { - m := testModule(t, "refresh-dynamic") - - startingState := states.BuildState(func(ss *states.SyncState) { - ss.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_instance", - Name: "foo", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"dynamic":{"type":"string","value":"hello"}}`), - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("test"), - Module: addrs.RootModule, - }, - ) - }) - - readStateVal := cty.ObjectVal(map[string]cty.Value{ - "dynamic": cty.EmptyTupleVal, - }) - - p := testProvider("test") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test_instance": { - Attributes: map[string]*configschema.Attribute{ - "dynamic": {Type: cty.DynamicPseudoType, Optional: true}, - }, - }, - }, - }) - p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse { - return providers.ReadResourceResponse{ - NewState: readStateVal, - } - } - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { - resp.PlannedState = req.ProposedNewState - return resp - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - schema := p.GetProviderSchemaResponse.ResourceTypes["test_instance"].Block - ty := schema.ImpliedType() - - s, diags := ctx.Refresh(m, startingState, &PlanOpts{Mode: plans.NormalMode}) - if diags.HasErrors() { - t.Fatal(diags.Err()) - } - - if !p.ReadResourceCalled { - t.Fatal("ReadResource should be called") - } - - mod := s.RootModule() - newState, err := mod.Resources["test_instance.foo"].Instances[addrs.NoKey].Current.Decode(ty) - if err != nil { - t.Fatal(err) - } - - if !cmp.Equal(readStateVal, newState.Value, valueComparer) { - t.Error(cmp.Diff(newState.Value, readStateVal, valueComparer, equateEmpty)) - } -} - -func TestContext2Refresh_dataComputedModuleVar(t *testing.T) { - p := testProvider("aws") - m := testModule(t, "refresh-data-module-var") - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { - obj := req.ProposedNewState.AsValueMap() - obj["id"] = cty.UnknownVal(cty.String) - resp.PlannedState = cty.ObjectVal(obj) - return resp - } - p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) { - resp.State = req.Config - return resp - } - - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - Provider: &configschema.Block{}, - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "foo": { - Type: cty.String, - Optional: true, - }, - "id": { - Type: cty.String, - Computed: true, - }, - }, - }, - }, - DataSources: map[string]*configschema.Block{ - "aws_data_source": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Optional: true, - }, - "output": { - Type: cty.String, - Computed: true, - }, - }, - }, - }, - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{Mode: plans.RefreshOnlyMode}) - if diags.HasErrors() { - t.Fatalf("refresh errors: %s", diags.Err()) - } - - checkStateString(t, plan.PriorState, ` - -`) -} - -func TestContext2Refresh_targeted(t *testing.T) { - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - Provider: &configschema.Block{}, - ResourceTypes: map[string]*configschema.Block{ - "aws_elb": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - "instances": { - Type: cty.Set(cty.String), - Optional: true, - }, - }, - }, - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - "vpc_id": { - Type: cty.String, - Optional: true, - }, - }, - }, - "aws_vpc": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - }, - }, - }, - }) - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - testSetResourceInstanceCurrent(root, "aws_vpc.metoo", `{"id":"vpc-abc123"}`, `provider["registry.terraform.io/hashicorp/aws"]`) - testSetResourceInstanceCurrent(root, "aws_instance.notme", `{"id":"i-bcd345"}`, `provider["registry.terraform.io/hashicorp/aws"]`) - testSetResourceInstanceCurrent(root, "aws_instance.me", `{"id":"i-abc123"}`, `provider["registry.terraform.io/hashicorp/aws"]`) - testSetResourceInstanceCurrent(root, "aws_elb.meneither", `{"id":"lb-abc123"}`, `provider["registry.terraform.io/hashicorp/aws"]`) - - m := testModule(t, "refresh-targeted") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - refreshedResources := make([]string, 0, 2) - p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse { - refreshedResources = append(refreshedResources, req.PriorState.GetAttr("id").AsString()) - return providers.ReadResourceResponse{ - NewState: req.PriorState, - } - } - - _, diags := ctx.Refresh(m, state, &PlanOpts{ - Mode: plans.NormalMode, - Targets: []addrs.Targetable{ - addrs.RootModuleInstance.Resource( - addrs.ManagedResourceMode, "aws_instance", "me", - ), - }, - }) - if diags.HasErrors() { - t.Fatalf("refresh errors: %s", diags.Err()) - } - - expected := []string{"vpc-abc123", "i-abc123"} - if !reflect.DeepEqual(refreshedResources, expected) { - t.Fatalf("expected: %#v, got: %#v", expected, refreshedResources) - } -} - -func TestContext2Refresh_targetedCount(t *testing.T) { - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - Provider: &configschema.Block{}, - ResourceTypes: map[string]*configschema.Block{ - "aws_elb": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - "instances": { - Type: cty.Set(cty.String), - Optional: true, - }, - }, - }, - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - "vpc_id": { - Type: cty.String, - Optional: true, - }, - }, - }, - "aws_vpc": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - }, - }, - }, - }) - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - testSetResourceInstanceCurrent(root, "aws_vpc.metoo", `{"id":"vpc-abc123"}`, `provider["registry.terraform.io/hashicorp/aws"]`) - testSetResourceInstanceCurrent(root, "aws_instance.notme", `{"id":"i-bcd345"}`, `provider["registry.terraform.io/hashicorp/aws"]`) - testSetResourceInstanceCurrent(root, "aws_instance.me[0]", `{"id":"i-abc123"}`, `provider["registry.terraform.io/hashicorp/aws"]`) - testSetResourceInstanceCurrent(root, "aws_instance.me[1]", `{"id":"i-cde567"}`, `provider["registry.terraform.io/hashicorp/aws"]`) - testSetResourceInstanceCurrent(root, "aws_instance.me[2]", `{"id":"i-cde789"}`, `provider["registry.terraform.io/hashicorp/aws"]`) - testSetResourceInstanceCurrent(root, "aws_elb.meneither", `{"id":"lb-abc123"}`, `provider["registry.terraform.io/hashicorp/aws"]`) - - m := testModule(t, "refresh-targeted-count") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - refreshedResources := make([]string, 0, 2) - p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse { - refreshedResources = append(refreshedResources, req.PriorState.GetAttr("id").AsString()) - return providers.ReadResourceResponse{ - NewState: req.PriorState, - } - } - - _, diags := ctx.Refresh(m, state, &PlanOpts{ - Mode: plans.NormalMode, - Targets: []addrs.Targetable{ - addrs.RootModuleInstance.Resource( - addrs.ManagedResourceMode, "aws_instance", "me", - ), - }, - }) - if diags.HasErrors() { - t.Fatalf("refresh errors: %s", diags.Err()) - } - - // Target didn't specify index, so we should get all our instances - expected := []string{ - "vpc-abc123", - "i-abc123", - "i-cde567", - "i-cde789", - } - sort.Strings(expected) - sort.Strings(refreshedResources) - if !reflect.DeepEqual(refreshedResources, expected) { - t.Fatalf("wrong result\ngot: %#v\nwant: %#v", refreshedResources, expected) - } -} - -func TestContext2Refresh_targetedCountIndex(t *testing.T) { - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - Provider: &configschema.Block{}, - ResourceTypes: map[string]*configschema.Block{ - "aws_elb": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - "instances": { - Type: cty.Set(cty.String), - Optional: true, - }, - }, - }, - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - "vpc_id": { - Type: cty.String, - Optional: true, - }, - }, - }, - "aws_vpc": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - }, - }, - }, - }) - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - testSetResourceInstanceCurrent(root, "aws_vpc.metoo", `{"id":"vpc-abc123"}`, `provider["registry.terraform.io/hashicorp/aws"]`) - testSetResourceInstanceCurrent(root, "aws_instance.notme", `{"id":"i-bcd345"}`, `provider["registry.terraform.io/hashicorp/aws"]`) - testSetResourceInstanceCurrent(root, "aws_instance.me[0]", `{"id":"i-abc123"}`, `provider["registry.terraform.io/hashicorp/aws"]`) - testSetResourceInstanceCurrent(root, "aws_instance.me[1]", `{"id":"i-cde567"}`, `provider["registry.terraform.io/hashicorp/aws"]`) - testSetResourceInstanceCurrent(root, "aws_instance.me[2]", `{"id":"i-cde789"}`, `provider["registry.terraform.io/hashicorp/aws"]`) - testSetResourceInstanceCurrent(root, "aws_elb.meneither", `{"id":"lb-abc123"}`, `provider["registry.terraform.io/hashicorp/aws"]`) - - m := testModule(t, "refresh-targeted-count") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - refreshedResources := make([]string, 0, 2) - p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse { - refreshedResources = append(refreshedResources, req.PriorState.GetAttr("id").AsString()) - return providers.ReadResourceResponse{ - NewState: req.PriorState, - } - } - - _, diags := ctx.Refresh(m, state, &PlanOpts{ - Mode: plans.NormalMode, - Targets: []addrs.Targetable{ - addrs.RootModuleInstance.ResourceInstance( - addrs.ManagedResourceMode, "aws_instance", "me", addrs.IntKey(0), - ), - }, - }) - if diags.HasErrors() { - t.Fatalf("refresh errors: %s", diags.Err()) - } - - expected := []string{"vpc-abc123", "i-abc123"} - if !reflect.DeepEqual(refreshedResources, expected) { - t.Fatalf("wrong result\ngot: %#v\nwant: %#v", refreshedResources, expected) - } -} - -func TestContext2Refresh_moduleComputedVar(t *testing.T) { - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - Provider: &configschema.Block{}, - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - "value": { - Type: cty.String, - Optional: true, - }, - }, - }, - }, - }) - - m := testModule(t, "refresh-module-computed-var") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - // This was failing (see GH-2188) at some point, so this test just - // verifies that the failure goes away. - if _, diags := ctx.Refresh(m, states.NewState(), &PlanOpts{Mode: plans.NormalMode}); diags.HasErrors() { - t.Fatalf("refresh errs: %s", diags.Err()) - } -} - -func TestContext2Refresh_delete(t *testing.T) { - p := testProvider("aws") - m := testModule(t, "refresh-basic") - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - testSetResourceInstanceCurrent(root, "aws_instance.web", `{"id":"foo"}`, `provider["registry.terraform.io/hashicorp/aws"]`) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - p.ReadResourceResponse = &providers.ReadResourceResponse{ - NewState: cty.NullVal(p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block.ImpliedType()), - } - - s, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode}) - if diags.HasErrors() { - t.Fatalf("refresh errors: %s", diags.Err()) - } - - mod := s.RootModule() - if len(mod.Resources) > 0 { - t.Fatal("resources should be empty") - } -} - -func TestContext2Refresh_ignoreUncreated(t *testing.T) { - p := testProvider("aws") - m := testModule(t, "refresh-basic") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - p.ReadResourceResponse = &providers.ReadResourceResponse{ - NewState: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("foo"), - }), - } - - _, diags := ctx.Refresh(m, states.NewState(), &PlanOpts{Mode: plans.NormalMode}) - if diags.HasErrors() { - t.Fatalf("refresh errors: %s", diags.Err()) - } - if p.ReadResourceCalled { - t.Fatal("refresh should not be called") - } -} - -func TestContext2Refresh_hook(t *testing.T) { - h := new(MockHook) - p := testProvider("aws") - m := testModule(t, "refresh-basic") - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - testSetResourceInstanceCurrent(root, "aws_instance.web", `{"id":"foo"}`, `provider["registry.terraform.io/hashicorp/aws"]`) - - ctx := testContext2(t, &ContextOpts{ - Hooks: []Hook{h}, - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - if _, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode}); diags.HasErrors() { - t.Fatalf("refresh errs: %s", diags.Err()) - } - if !h.PreRefreshCalled { - t.Fatal("should be called") - } - if !h.PostRefreshCalled { - t.Fatal("should be called") - } -} - -func TestContext2Refresh_modules(t *testing.T) { - p := testProvider("aws") - m := testModule(t, "refresh-modules") - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - testSetResourceInstanceTainted(root, "aws_instance.web", `{"id":"bar"}`, `provider["registry.terraform.io/hashicorp/aws"]`) - child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey)) - testSetResourceInstanceCurrent(child, "aws_instance.web", `{"id":"baz"}`, `provider["registry.terraform.io/hashicorp/aws"]`) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse { - if !req.PriorState.GetAttr("id").RawEquals(cty.StringVal("baz")) { - return providers.ReadResourceResponse{ - NewState: req.PriorState, - } - } - - new, _ := cty.Transform(req.PriorState, func(path cty.Path, v cty.Value) (cty.Value, error) { - if len(path) == 1 && path[0].(cty.GetAttrStep).Name == "id" { - return cty.StringVal("new"), nil - } - return v, nil - }) - return providers.ReadResourceResponse{ - NewState: new, - } - } - - s, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode}) - if diags.HasErrors() { - t.Fatalf("refresh errors: %s", diags.Err()) - } - - actual := strings.TrimSpace(s.String()) - expected := strings.TrimSpace(testContextRefreshModuleStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestContext2Refresh_moduleInputComputedOutput(t *testing.T) { - m := testModule(t, "refresh-module-input-computed-output") - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - Provider: &configschema.Block{}, - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "foo": { - Type: cty.String, - Optional: true, - Computed: true, - }, - "compute": { - Type: cty.String, - Optional: true, - }, - }, - }, - }, - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - if _, diags := ctx.Refresh(m, states.NewState(), &PlanOpts{Mode: plans.NormalMode}); diags.HasErrors() { - t.Fatalf("refresh errs: %s", diags.Err()) - } -} - -func TestContext2Refresh_moduleVarModule(t *testing.T) { - m := testModule(t, "refresh-module-var-module") - p := testProvider("aws") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - if _, diags := ctx.Refresh(m, states.NewState(), &PlanOpts{Mode: plans.NormalMode}); diags.HasErrors() { - t.Fatalf("refresh errs: %s", diags.Err()) - } -} - -// GH-70 -func TestContext2Refresh_noState(t *testing.T) { - p := testProvider("aws") - m := testModule(t, "refresh-no-state") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - p.ReadResourceResponse = &providers.ReadResourceResponse{ - NewState: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("foo"), - }), - } - - if _, diags := ctx.Refresh(m, states.NewState(), &PlanOpts{Mode: plans.NormalMode}); diags.HasErrors() { - t.Fatalf("refresh errs: %s", diags.Err()) - } -} - -func TestContext2Refresh_output(t *testing.T) { - p := testProvider("aws") - p.PlanResourceChangeFn = testDiffFn - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - Provider: &configschema.Block{}, - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - "foo": { - Type: cty.String, - Optional: true, - Computed: true, - }, - }, - }, - }, - }) - - m := testModule(t, "refresh-output") - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - testSetResourceInstanceCurrent(root, "aws_instance.web", `{"id":"foo","foo":"bar"}`, `provider["registry.terraform.io/hashicorp/aws"]`) - root.SetOutputValue("foo", cty.StringVal("foo"), false) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - s, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode}) - if diags.HasErrors() { - t.Fatalf("refresh errors: %s", diags.Err()) - } - - actual := strings.TrimSpace(s.String()) - expected := strings.TrimSpace(testContextRefreshOutputStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%q\n\nwant:\n%q", actual, expected) - } -} - -func TestContext2Refresh_outputPartial(t *testing.T) { - p := testProvider("aws") - m := testModule(t, "refresh-output-partial") - - // Refresh creates a partial plan for any instances that don't have - // remote objects yet, to get stub values for interpolation. Therefore - // we need to make DiffFn available to let that complete. - - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - Provider: &configschema.Block{}, - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "foo": { - Type: cty.String, - Computed: true, - }, - }, - }, - }, - }) - - p.ReadResourceResponse = &providers.ReadResourceResponse{ - NewState: cty.NullVal(p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block.ImpliedType()), - } - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - testSetResourceInstanceCurrent(root, "aws_instance.foo", `{}`, `provider["registry.terraform.io/hashicorp/aws"]`) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - s, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode}) - if diags.HasErrors() { - t.Fatalf("refresh errors: %s", diags.Err()) - } - - actual := strings.TrimSpace(s.String()) - expected := strings.TrimSpace(testContextRefreshOutputPartialStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestContext2Refresh_stateBasic(t *testing.T) { - p := testProvider("aws") - m := testModule(t, "refresh-basic") - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - testSetResourceInstanceCurrent(root, "aws_instance.web", `{"id":"bar"}`, `provider["registry.terraform.io/hashicorp/aws"]`) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block - ty := schema.ImpliedType() - - readStateVal, err := schema.CoerceValue(cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("foo"), - })) - if err != nil { - t.Fatal(err) - } - - p.ReadResourceResponse = &providers.ReadResourceResponse{ - NewState: readStateVal, - } - - s, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode}) - if diags.HasErrors() { - t.Fatalf("refresh errors: %s", diags.Err()) - } - - if !p.ReadResourceCalled { - t.Fatal("read resource should be called") - } - - mod := s.RootModule() - newState, err := mod.Resources["aws_instance.web"].Instances[addrs.NoKey].Current.Decode(ty) - if err != nil { - t.Fatal(err) - } - - if !cmp.Equal(readStateVal, newState.Value, valueComparer, equateEmpty) { - t.Fatal(cmp.Diff(readStateVal, newState.Value, valueComparer, equateEmpty)) - } -} - -func TestContext2Refresh_dataCount(t *testing.T) { - p := testProvider("test") - m := testModule(t, "refresh-data-count") - - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { - m := req.ProposedNewState.AsValueMap() - m["things"] = cty.ListVal([]cty.Value{cty.StringVal("foo")}) - resp.PlannedState = cty.ObjectVal(m) - return resp - } - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test": { - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Computed: true}, - "things": {Type: cty.List(cty.String), Computed: true}, - }, - }, - }, - DataSources: map[string]*configschema.Block{ - "test": {}, - }, - }) - - p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse { - return providers.ReadDataSourceResponse{ - State: req.Config, - } - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - s, diags := ctx.Refresh(m, states.NewState(), &PlanOpts{Mode: plans.NormalMode}) - - if diags.HasErrors() { - t.Fatalf("refresh errors: %s", diags.Err()) - } - - checkStateString(t, s, ``) -} - -func TestContext2Refresh_dataState(t *testing.T) { - m := testModule(t, "refresh-data-resource-basic") - state := states.NewState() - schema := &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "inputs": { - Type: cty.Map(cty.String), - Optional: true, - }, - }, - } - - p := testProvider("null") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - Provider: &configschema.Block{}, - DataSources: map[string]*configschema.Block{ - "null_data_source": schema, - }, - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("null"): testProviderFuncFixed(p), - }, - }) - - var readStateVal cty.Value - - p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse { - m := req.Config.AsValueMap() - readStateVal = cty.ObjectVal(m) - - return providers.ReadDataSourceResponse{ - State: readStateVal, - } - } - - s, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode}) - if diags.HasErrors() { - t.Fatalf("refresh errors: %s", diags.Err()) - } - - if !p.ReadDataSourceCalled { - t.Fatal("ReadDataSource should have been called") - } - - mod := s.RootModule() - - newState, err := mod.Resources["data.null_data_source.testing"].Instances[addrs.NoKey].Current.Decode(schema.ImpliedType()) - if err != nil { - t.Fatal(err) - } - - if !cmp.Equal(readStateVal, newState.Value, valueComparer, equateEmpty) { - t.Fatal(cmp.Diff(readStateVal, newState.Value, valueComparer, equateEmpty)) - } -} - -func TestContext2Refresh_dataStateRefData(t *testing.T) { - p := testProvider("null") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - Provider: &configschema.Block{}, - DataSources: map[string]*configschema.Block{ - "null_data_source": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - "foo": { - Type: cty.String, - Optional: true, - }, - "bar": { - Type: cty.String, - Optional: true, - }, - }, - }, - }, - }) - - m := testModule(t, "refresh-data-ref-data") - state := states.NewState() - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("null"): testProviderFuncFixed(p), - }, - }) - - p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse { - // add the required id - m := req.Config.AsValueMap() - m["id"] = cty.StringVal("foo") - - return providers.ReadDataSourceResponse{ - State: cty.ObjectVal(m), - } - } - - s, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode}) - if diags.HasErrors() { - t.Fatalf("refresh errors: %s", diags.Err()) - } - - actual := strings.TrimSpace(s.String()) - expected := strings.TrimSpace(testTerraformRefreshDataRefDataStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestContext2Refresh_tainted(t *testing.T) { - p := testProvider("aws") - m := testModule(t, "refresh-basic") - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - testSetResourceInstanceTainted(root, "aws_instance.web", `{"id":"bar"}`, `provider["registry.terraform.io/hashicorp/aws"]`) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse { - // add the required id - m := req.PriorState.AsValueMap() - m["id"] = cty.StringVal("foo") - - return providers.ReadResourceResponse{ - NewState: cty.ObjectVal(m), - } - } - - s, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode}) - if diags.HasErrors() { - t.Fatalf("refresh errors: %s", diags.Err()) - } - if !p.ReadResourceCalled { - t.Fatal("ReadResource was not called; should have been") - } - - actual := strings.TrimSpace(s.String()) - expected := strings.TrimSpace(testContextRefreshTaintedStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -// Doing a Refresh (or any operation really, but Refresh usually -// happens first) with a config with an unknown provider should result in -// an error. The key bug this found was that this wasn't happening if -// Providers was _empty_. -func TestContext2Refresh_unknownProvider(t *testing.T) { - m := testModule(t, "refresh-unknown-provider") - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - testSetResourceInstanceCurrent(root, "aws_instance.web", `{"id":"foo"}`, `provider["registry.terraform.io/hashicorp/aws"]`) - - c, diags := NewContext(&ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{}, - }) - assertNoDiagnostics(t, diags) - - _, diags = c.Refresh(m, states.NewState(), &PlanOpts{Mode: plans.NormalMode}) - if !diags.HasErrors() { - t.Fatal("successfully refreshed; want error") - } - - if got, want := diags.Err().Error(), "Missing required provider"; !strings.Contains(got, want) { - t.Errorf("missing expected error\nwant substring: %s\ngot:\n%s", want, got) - } -} - -func TestContext2Refresh_vars(t *testing.T) { - p := testProvider("aws") - - schema := &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "ami": { - Type: cty.String, - Optional: true, - }, - "id": { - Type: cty.String, - Computed: true, - }, - }, - } - - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - Provider: &configschema.Block{}, - ResourceTypes: map[string]*configschema.Block{"aws_instance": schema}, - }) - - m := testModule(t, "refresh-vars") - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - testSetResourceInstanceCurrent(root, "aws_instance.web", `{"id":"foo"}`, `provider["registry.terraform.io/hashicorp/aws"]`) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - readStateVal, err := schema.CoerceValue(cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("foo"), - })) - if err != nil { - t.Fatal(err) - } - - p.ReadResourceResponse = &providers.ReadResourceResponse{ - NewState: readStateVal, - } - - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse { - return providers.PlanResourceChangeResponse{ - PlannedState: req.ProposedNewState, - } - } - - s, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode}) - if diags.HasErrors() { - t.Fatalf("refresh errors: %s", diags.Err()) - } - - if !p.ReadResourceCalled { - t.Fatal("read resource should be called") - } - - mod := s.RootModule() - - newState, err := mod.Resources["aws_instance.web"].Instances[addrs.NoKey].Current.Decode(schema.ImpliedType()) - if err != nil { - t.Fatal(err) - } - - if !cmp.Equal(readStateVal, newState.Value, valueComparer, equateEmpty) { - t.Fatal(cmp.Diff(readStateVal, newState.Value, valueComparer, equateEmpty)) - } - - for _, r := range mod.Resources { - if r.Addr.Resource.Type == "" { - t.Fatalf("no type: %#v", r) - } - } -} - -func TestContext2Refresh_orphanModule(t *testing.T) { - p := testProvider("aws") - m := testModule(t, "refresh-module-orphan") - - // Create a custom refresh function to track the order they were visited - var order []string - var orderLock sync.Mutex - p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse { - orderLock.Lock() - defer orderLock.Unlock() - - order = append(order, req.PriorState.GetAttr("id").AsString()) - return providers.ReadResourceResponse{ - NewState: req.PriorState, - } - } - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"i-abc123"}`), - Dependencies: []addrs.ConfigResource{ - {Module: addrs.Module{"module.child"}}, - {Module: addrs.Module{"module.child"}}, - }, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey)) - child.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.bar").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"i-bcd23"}`), - Dependencies: []addrs.ConfigResource{{Module: addrs.Module{"module.grandchild"}}}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - grandchild := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey).Child("grandchild", addrs.NoKey)) - testSetResourceInstanceCurrent(grandchild, "aws_instance.baz", `{"id":"i-cde345"}`, `provider["registry.terraform.io/hashicorp/aws"]`) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - testCheckDeadlock(t, func() { - _, err := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode}) - if err != nil { - t.Fatalf("err: %s", err.Err()) - } - - // TODO: handle order properly for orphaned modules / resources - // expected := []string{"i-abc123", "i-bcd234", "i-cde345"} - // if !reflect.DeepEqual(order, expected) { - // t.Fatalf("expected: %#v, got: %#v", expected, order) - // } - }) -} - -func TestContext2Validate(t *testing.T) { - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - Provider: &configschema.Block{}, - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "foo": { - Type: cty.String, - Optional: true, - }, - "num": { - Type: cty.String, - Optional: true, - }, - }, - }, - }, - }) - - m := testModule(t, "validate-good") - c := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := c.Validate(m) - if len(diags) != 0 { - t.Fatalf("unexpected error: %#v", diags.ErrWithWarnings()) - } -} - -func TestContext2Refresh_updateProviderInState(t *testing.T) { - m := testModule(t, "update-resource-provider") - p := testProvider("aws") - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - testSetResourceInstanceCurrent(root, "aws_instance.bar", `{"id":"foo"}`, `provider["registry.terraform.io/hashicorp/aws"].baz`) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - expected := strings.TrimSpace(` -aws_instance.bar: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"].foo`) - - s, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode}) - if diags.HasErrors() { - t.Fatal(diags.Err()) - } - - actual := s.String() - if actual != expected { - t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) - } -} - -func TestContext2Refresh_schemaUpgradeFlatmap(t *testing.T) { - m := testModule(t, "refresh-schema-upgrade") - p := testProvider("test") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test_thing": { - Attributes: map[string]*configschema.Attribute{ - "name": { // imagining we renamed this from "id" - Type: cty.String, - Optional: true, - }, - }, - }, - }, - ResourceTypeSchemaVersions: map[string]uint64{ - "test_thing": 5, - }, - }) - p.UpgradeResourceStateResponse = &providers.UpgradeResourceStateResponse{ - UpgradedState: cty.ObjectVal(map[string]cty.Value{ - "name": cty.StringVal("foo"), - }), - } - - s := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_thing", - Name: "bar", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - SchemaVersion: 3, - AttrsFlat: map[string]string{ - "id": "foo", - }, - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("test"), - Module: addrs.RootModule, - }, - ) - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - state, diags := ctx.Refresh(m, s, &PlanOpts{Mode: plans.NormalMode}) - if diags.HasErrors() { - t.Fatal(diags.Err()) - } - - { - got := p.UpgradeResourceStateRequest - want := providers.UpgradeResourceStateRequest{ - TypeName: "test_thing", - Version: 3, - RawStateFlatmap: map[string]string{ - "id": "foo", - }, - } - if !cmp.Equal(got, want) { - t.Errorf("wrong upgrade request\n%s", cmp.Diff(want, got)) - } - } - - { - got := state.String() - want := strings.TrimSpace(` -test_thing.bar: - ID = - provider = provider["registry.terraform.io/hashicorp/test"] - name = foo -`) - if got != want { - t.Fatalf("wrong result state\ngot:\n%s\n\nwant:\n%s", got, want) - } - } -} - -func TestContext2Refresh_schemaUpgradeJSON(t *testing.T) { - m := testModule(t, "refresh-schema-upgrade") - p := testProvider("test") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test_thing": { - Attributes: map[string]*configschema.Attribute{ - "name": { // imagining we renamed this from "id" - Type: cty.String, - Optional: true, - }, - }, - }, - }, - ResourceTypeSchemaVersions: map[string]uint64{ - "test_thing": 5, - }, - }) - p.UpgradeResourceStateResponse = &providers.UpgradeResourceStateResponse{ - UpgradedState: cty.ObjectVal(map[string]cty.Value{ - "name": cty.StringVal("foo"), - }), - } - - s := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_thing", - Name: "bar", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - SchemaVersion: 3, - AttrsJSON: []byte(`{"id":"foo"}`), - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("test"), - Module: addrs.RootModule, - }, - ) - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - state, diags := ctx.Refresh(m, s, &PlanOpts{Mode: plans.NormalMode}) - if diags.HasErrors() { - t.Fatal(diags.Err()) - } - - { - got := p.UpgradeResourceStateRequest - want := providers.UpgradeResourceStateRequest{ - TypeName: "test_thing", - Version: 3, - RawStateJSON: []byte(`{"id":"foo"}`), - } - if !cmp.Equal(got, want) { - t.Errorf("wrong upgrade request\n%s", cmp.Diff(want, got)) - } - } - - { - got := state.String() - want := strings.TrimSpace(` -test_thing.bar: - ID = - provider = provider["registry.terraform.io/hashicorp/test"] - name = foo -`) - if got != want { - t.Fatalf("wrong result state\ngot:\n%s\n\nwant:\n%s", got, want) - } - } -} - -func TestContext2Refresh_dataValidation(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -data "aws_data_source" "foo" { - foo = "bar" -} -`, - }) - - p := testProvider("aws") - p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { - resp.PlannedState = req.ProposedNewState - return - } - p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) { - resp.State = req.Config - return - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - _, diags := ctx.Refresh(m, states.NewState(), &PlanOpts{Mode: plans.NormalMode}) - if diags.HasErrors() { - // Should get this error: - // Unsupported attribute: This object does not have an attribute named "missing" - t.Fatal(diags.Err()) - } - - if !p.ValidateDataResourceConfigCalled { - t.Fatal("ValidateDataSourceConfig not called during plan") - } -} - -func TestContext2Refresh_dataResourceDependsOn(t *testing.T) { - m := testModule(t, "plan-data-depends-on") - p := testProvider("test") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test_resource": { - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Computed: true}, - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - DataSources: map[string]*configschema.Block{ - "test_data": { - Attributes: map[string]*configschema.Attribute{ - "compute": {Type: cty.String, Computed: true}, - }, - }, - }, - }) - p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{ - State: cty.ObjectVal(map[string]cty.Value{ - "compute": cty.StringVal("value"), - }), - } - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - testSetResourceInstanceCurrent(root, "test_resource.a", `{"id":"a"}`, `provider["registry.terraform.io/hashicorp/test"]`) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - _, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode}) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } -} - -// verify that create_before_destroy is updated in the state during refresh -func TestRefresh_updateLifecycle(t *testing.T) { - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "bar", - }.Instance(addrs.NoKey), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("aws"), - Module: addrs.RootModule, - }, - ) - - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "aws_instance" "bar" { - lifecycle { - create_before_destroy = true - } -} -`, - }) - - p := testProvider("aws") - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - state, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode}) - if diags.HasErrors() { - t.Fatalf("plan errors: %s", diags.Err()) - } - - r := state.ResourceInstance(mustResourceInstanceAddr("aws_instance.bar")) - if !r.Current.CreateBeforeDestroy { - t.Fatal("create_before_destroy not updated in instance state") - } -} - -func TestContext2Refresh_dataSourceOrphan(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ``, - }) - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.DataResourceMode, - Type: "test_data_source", - Name: "foo", - }.Instance(addrs.NoKey), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo"}`), - Dependencies: []addrs.ConfigResource{}, - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("test"), - Module: addrs.RootModule, - }, - ) - p := testProvider("test") - p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) { - resp.State = cty.NullVal(req.Config.Type()) - return - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - _, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode}) - if diags.HasErrors() { - t.Fatal(diags.Err()) - } - - if p.ReadResourceCalled { - t.Fatal("there are no managed resources to read") - } - - if p.ReadDataSourceCalled { - t.Fatal("orphaned data source instance should not be read") - } -} - -// Legacy providers may return invalid null values for blocks, causing noise in -// the diff output and unexpected behavior with ignore_changes. Make sure -// refresh fixes these up before storing the state. -func TestContext2Refresh_reifyNullBlock(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "test_resource" "foo" { -} -`, - }) - - p := new(MockProvider) - p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse { - // incorrectly return a null _set_block value - v := req.PriorState.AsValueMap() - v["set_block"] = cty.NullVal(v["set_block"].Type()) - return providers.ReadResourceResponse{NewState: cty.ObjectVal(v)} - } - - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - Provider: &configschema.Block{}, - ResourceTypes: map[string]*configschema.Block{ - "test_resource": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - }, - BlockTypes: map[string]*configschema.NestedBlock{ - "set_block": { - Block: configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "a": {Type: cty.String, Optional: true}, - }, - }, - Nesting: configschema.NestingSet, - }, - }, - }, - }, - }) - p.PlanResourceChangeFn = testDiffFn - - fooAddr := addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_resource", - Name: "foo", - }.Instance(addrs.NoKey) - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - fooAddr, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo", "network_interface":[]}`), - Dependencies: []addrs.ConfigResource{}, - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("test"), - Module: addrs.RootModule, - }, - ) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - plan, diags := ctx.Plan(m, state, &PlanOpts{Mode: plans.RefreshOnlyMode}) - if diags.HasErrors() { - t.Fatalf("refresh errors: %s", diags.Err()) - } - - jsonState := plan.PriorState.ResourceInstance(fooAddr.Absolute(addrs.RootModuleInstance)).Current.AttrsJSON - - // the set_block should still be an empty container, and not null - expected := `{"id":"foo","set_block":[]}` - if string(jsonState) != expected { - t.Fatalf("invalid state\nexpected: %s\ngot: %s\n", expected, jsonState) - } -} diff --git a/internal/terraform/context_test.go b/internal/terraform/context_test.go deleted file mode 100644 index 12c376622b1c..000000000000 --- a/internal/terraform/context_test.go +++ /dev/null @@ -1,1005 +0,0 @@ -package terraform - -import ( - "bufio" - "bytes" - "fmt" - "path/filepath" - "sort" - "strings" - "testing" - "time" - - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" - "github.com/hashicorp/go-version" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configload" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/configs/hcl2shim" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/plans/planfile" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/provisioners" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/statefile" - "github.com/hashicorp/terraform/internal/tfdiags" - tfversion "github.com/hashicorp/terraform/version" - "github.com/zclconf/go-cty/cty" -) - -var ( - equateEmpty = cmpopts.EquateEmpty() - typeComparer = cmp.Comparer(cty.Type.Equals) - valueComparer = cmp.Comparer(cty.Value.RawEquals) - valueTrans = cmp.Transformer("hcl2shim", hcl2shim.ConfigValueFromHCL2) -) - -func TestNewContextRequiredVersion(t *testing.T) { - cases := []struct { - Name string - Module string - Version string - Value string - Err bool - }{ - { - "no requirement", - "", - "0.1.0", - "", - false, - }, - - { - "doesn't match", - "", - "0.1.0", - "> 0.6.0", - true, - }, - - { - "matches", - "", - "0.7.0", - "> 0.6.0", - false, - }, - - { - "prerelease doesn't match with inequality", - "", - "0.8.0", - "> 0.7.0-beta", - true, - }, - - { - "prerelease doesn't match with equality", - "", - "0.7.0", - "0.7.0-beta", - true, - }, - - { - "module matches", - "context-required-version-module", - "0.5.0", - "", - false, - }, - - { - "module doesn't match", - "context-required-version-module", - "0.4.0", - "", - true, - }, - } - - for i, tc := range cases { - t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) { - // Reset the version for the tests - old := tfversion.SemVer - tfversion.SemVer = version.Must(version.NewVersion(tc.Version)) - defer func() { tfversion.SemVer = old }() - - name := "context-required-version" - if tc.Module != "" { - name = tc.Module - } - mod := testModule(t, name) - if tc.Value != "" { - constraint, err := version.NewConstraint(tc.Value) - if err != nil { - t.Fatalf("can't parse %q as version constraint", tc.Value) - } - mod.Module.CoreVersionConstraints = append(mod.Module.CoreVersionConstraints, configs.VersionConstraint{ - Required: constraint, - }) - } - c, diags := NewContext(&ContextOpts{}) - if diags.HasErrors() { - t.Fatalf("unexpected NewContext errors: %s", diags.Err()) - } - - diags = c.Validate(mod) - if diags.HasErrors() != tc.Err { - t.Fatalf("err: %s", diags.Err()) - } - }) - } -} - -func TestContext_missingPlugins(t *testing.T) { - ctx, diags := NewContext(&ContextOpts{}) - assertNoDiagnostics(t, diags) - - configSrc := ` -terraform { - required_providers { - explicit = { - source = "example.com/foo/beep" - } - builtin = { - source = "terraform.io/builtin/nonexist" - } - } -} - -resource "implicit_thing" "a" { - provisioner "nonexist" { - } -} - -resource "implicit_thing" "b" { - provider = implicit2 -} -` - - cfg := testModuleInline(t, map[string]string{ - "main.tf": configSrc, - }) - - // Validate and Plan are the two entry points where we explicitly verify - // the available plugins match what the configuration needs. For other - // operations we typically fail more deeply in Terraform Core, with - // potentially-less-helpful error messages, because getting there would - // require doing some pretty weird things that aren't common enough to - // be worth the complexity to check for them. - - validateDiags := ctx.Validate(cfg) - _, planDiags := ctx.Plan(cfg, nil, DefaultPlanOpts) - - tests := map[string]tfdiags.Diagnostics{ - "validate": validateDiags, - "plan": planDiags, - } - - for testName, gotDiags := range tests { - t.Run(testName, func(t *testing.T) { - var wantDiags tfdiags.Diagnostics - wantDiags = wantDiags.Append( - tfdiags.Sourceless( - tfdiags.Error, - "Missing required provider", - "This configuration requires built-in provider terraform.io/builtin/nonexist, but that provider isn't available in this Terraform version.", - ), - tfdiags.Sourceless( - tfdiags.Error, - "Missing required provider", - "This configuration requires provider example.com/foo/beep, but that provider isn't available. You may be able to install it automatically by running:\n terraform init", - ), - tfdiags.Sourceless( - tfdiags.Error, - "Missing required provider", - "This configuration requires provider registry.terraform.io/hashicorp/implicit, but that provider isn't available. You may be able to install it automatically by running:\n terraform init", - ), - tfdiags.Sourceless( - tfdiags.Error, - "Missing required provider", - "This configuration requires provider registry.terraform.io/hashicorp/implicit2, but that provider isn't available. You may be able to install it automatically by running:\n terraform init", - ), - tfdiags.Sourceless( - tfdiags.Error, - "Missing required provisioner plugin", - `This configuration requires provisioner plugin "nonexist", which isn't available. If you're intending to use an external provisioner plugin, you must install it manually into one of the plugin search directories before running Terraform.`, - ), - ) - assertDiagnosticsMatch(t, gotDiags, wantDiags) - }) - } -} - -func testContext2(t *testing.T, opts *ContextOpts) *Context { - t.Helper() - - ctx, diags := NewContext(opts) - if diags.HasErrors() { - t.Fatalf("failed to create test context\n\n%s\n", diags.Err()) - } - - return ctx -} - -func testApplyFn(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - resp.NewState = req.PlannedState - if req.PlannedState.IsNull() { - resp.NewState = cty.NullVal(req.PriorState.Type()) - return - } - - planned := req.PlannedState.AsValueMap() - if planned == nil { - planned = map[string]cty.Value{} - } - - id, ok := planned["id"] - if !ok || id.IsNull() || !id.IsKnown() { - planned["id"] = cty.StringVal("foo") - } - - // our default schema has a computed "type" attr - if ty, ok := planned["type"]; ok && !ty.IsNull() { - planned["type"] = cty.StringVal(req.TypeName) - } - - if cmp, ok := planned["compute"]; ok && !cmp.IsNull() { - computed := cmp.AsString() - if val, ok := planned[computed]; ok && !val.IsKnown() { - planned[computed] = cty.StringVal("computed_value") - } - } - - for k, v := range planned { - if k == "unknown" { - // "unknown" should cause an error - continue - } - - if !v.IsKnown() { - switch k { - case "type": - planned[k] = cty.StringVal(req.TypeName) - default: - planned[k] = cty.NullVal(v.Type()) - } - } - } - - resp.NewState = cty.ObjectVal(planned) - return -} - -func testDiffFn(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { - var planned map[string]cty.Value - - // this is a destroy plan - if req.ProposedNewState.IsNull() { - resp.PlannedState = req.ProposedNewState - resp.PlannedPrivate = req.PriorPrivate - return resp - } - - if !req.ProposedNewState.IsNull() { - planned = req.ProposedNewState.AsValueMap() - } - if planned == nil { - planned = map[string]cty.Value{} - } - - // id is always computed for the tests - if id, ok := planned["id"]; ok && id.IsNull() { - planned["id"] = cty.UnknownVal(cty.String) - } - - // the old tests have require_new replace on every plan - if _, ok := planned["require_new"]; ok { - resp.RequiresReplace = append(resp.RequiresReplace, cty.Path{cty.GetAttrStep{Name: "require_new"}}) - } - - for k := range planned { - requiresNewKey := "__" + k + "_requires_new" - _, ok := planned[requiresNewKey] - if ok { - resp.RequiresReplace = append(resp.RequiresReplace, cty.Path{cty.GetAttrStep{Name: requiresNewKey}}) - } - } - - if v, ok := planned["compute"]; ok && !v.IsNull() { - k := v.AsString() - unknown := cty.UnknownVal(cty.String) - if strings.HasSuffix(k, ".#") { - k = k[:len(k)-2] - unknown = cty.UnknownVal(cty.List(cty.String)) - } - planned[k] = unknown - } - - if t, ok := planned["type"]; ok && t.IsNull() { - planned["type"] = cty.UnknownVal(cty.String) - } - - resp.PlannedState = cty.ObjectVal(planned) - return -} - -func testProvider(prefix string) *MockProvider { - p := new(MockProvider) - p.GetProviderSchemaResponse = testProviderSchema(prefix) - - return p -} - -func testProvisioner() *MockProvisioner { - p := new(MockProvisioner) - p.GetSchemaResponse = provisioners.GetSchemaResponse{ - Provisioner: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "command": { - Type: cty.String, - Optional: true, - }, - "order": { - Type: cty.String, - Optional: true, - }, - "when": { - Type: cty.String, - Optional: true, - }, - }, - }, - } - return p -} - -func checkStateString(t *testing.T, state *states.State, expected string) { - t.Helper() - actual := strings.TrimSpace(state.String()) - expected = strings.TrimSpace(expected) - - if actual != expected { - t.Fatalf("incorrect state\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -// Test helper that gives a function 3 seconds to finish, assumes deadlock and -// fails test if it does not. -func testCheckDeadlock(t *testing.T, f func()) { - t.Helper() - timeout := make(chan bool, 1) - done := make(chan bool, 1) - go func() { - time.Sleep(3 * time.Second) - timeout <- true - }() - go func(f func(), done chan bool) { - defer func() { done <- true }() - f() - }(f, done) - select { - case <-timeout: - t.Fatalf("timed out! probably deadlock") - case <-done: - // ok - } -} - -func testProviderSchema(name string) *providers.GetProviderSchemaResponse { - return getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - Provider: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "region": { - Type: cty.String, - Optional: true, - }, - "foo": { - Type: cty.String, - Optional: true, - }, - "value": { - Type: cty.String, - Optional: true, - }, - "root": { - Type: cty.Number, - Optional: true, - }, - }, - }, - ResourceTypes: map[string]*configschema.Block{ - name + "_instance": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - "ami": { - Type: cty.String, - Optional: true, - }, - "dep": { - Type: cty.String, - Optional: true, - }, - "num": { - Type: cty.Number, - Optional: true, - }, - "require_new": { - Type: cty.String, - Optional: true, - }, - "var": { - Type: cty.String, - Optional: true, - }, - "foo": { - Type: cty.String, - Optional: true, - Computed: true, - }, - "bar": { - Type: cty.String, - Optional: true, - }, - "compute": { - Type: cty.String, - Optional: true, - Computed: false, - }, - "compute_value": { - Type: cty.String, - Optional: true, - Computed: true, - }, - "value": { - Type: cty.String, - Optional: true, - Computed: true, - }, - "output": { - Type: cty.String, - Optional: true, - }, - "write": { - Type: cty.String, - Optional: true, - }, - "instance": { - Type: cty.String, - Optional: true, - }, - "vpc_id": { - Type: cty.String, - Optional: true, - }, - "type": { - Type: cty.String, - Computed: true, - }, - - // Generated by testDiffFn if compute = "unknown" is set in the test config - "unknown": { - Type: cty.String, - Computed: true, - }, - }, - }, - name + "_eip": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - "instance": { - Type: cty.String, - Optional: true, - }, - }, - }, - name + "_resource": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - "value": { - Type: cty.String, - Optional: true, - }, - "sensitive_value": { - Type: cty.String, - Sensitive: true, - Optional: true, - }, - "random": { - Type: cty.String, - Optional: true, - }, - }, - BlockTypes: map[string]*configschema.NestedBlock{ - "nesting_single": { - Block: configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "value": {Type: cty.String, Optional: true}, - "sensitive_value": {Type: cty.String, Optional: true, Sensitive: true}, - }, - }, - Nesting: configschema.NestingSingle, - }, - }, - }, - name + "_ami_list": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Optional: true, - Computed: true, - }, - "ids": { - Type: cty.List(cty.String), - Optional: true, - Computed: true, - }, - }, - }, - name + "_remote_state": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Optional: true, - }, - "foo": { - Type: cty.String, - Optional: true, - }, - "output": { - Type: cty.Map(cty.String), - Computed: true, - }, - }, - }, - name + "_file": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Optional: true, - }, - "template": { - Type: cty.String, - Optional: true, - }, - "rendered": { - Type: cty.String, - Computed: true, - }, - "__template_requires_new": { - Type: cty.String, - Optional: true, - }, - }, - }, - }, - DataSources: map[string]*configschema.Block{ - name + "_data_source": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - "foo": { - Type: cty.String, - Optional: true, - Computed: true, - }, - }, - }, - name + "_remote_state": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Optional: true, - }, - "foo": { - Type: cty.String, - Optional: true, - }, - "output": { - Type: cty.Map(cty.String), - Optional: true, - }, - }, - }, - name + "_file": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Optional: true, - }, - "template": { - Type: cty.String, - Optional: true, - }, - "rendered": { - Type: cty.String, - Computed: true, - }, - }, - }, - }, - }) -} - -// contextOptsForPlanViaFile is a helper that creates a temporary plan file, -// then reads it back in again and produces a ContextOpts object containing the -// planned changes, prior state and config from the plan file. -// -// This is intended for testing the separated plan/apply workflow in a more -// convenient way than spelling out all of these steps every time. Normally -// only the command and backend packages need to deal with such things, but -// our context tests try to exercise lots of stuff at once and so having them -// round-trip things through on-disk files is often an important part of -// fully representing an old bug in a regression test. -func contextOptsForPlanViaFile(t *testing.T, configSnap *configload.Snapshot, plan *plans.Plan) (*ContextOpts, *configs.Config, *plans.Plan, error) { - dir := t.TempDir() - - // We'll just create a dummy statefile.File here because we're not going - // to run through any of the codepaths that care about Lineage/Serial/etc - // here anyway. - stateFile := &statefile.File{ - State: plan.PriorState, - } - prevStateFile := &statefile.File{ - State: plan.PrevRunState, - } - - // To make life a little easier for test authors, we'll populate a simple - // backend configuration if they didn't set one, since the backend is - // usually dealt with in a calling package and so tests in this package - // don't really care about it. - if plan.Backend.Config == nil { - cfg, err := plans.NewDynamicValue(cty.EmptyObjectVal, cty.EmptyObject) - if err != nil { - panic(fmt.Sprintf("NewDynamicValue failed: %s", err)) // shouldn't happen because we control the inputs - } - plan.Backend.Type = "local" - plan.Backend.Config = cfg - plan.Backend.Workspace = "default" - } - - filename := filepath.Join(dir, "tfplan") - err := planfile.Create(filename, planfile.CreateArgs{ - ConfigSnapshot: configSnap, - PreviousRunStateFile: prevStateFile, - StateFile: stateFile, - Plan: plan, - }) - if err != nil { - return nil, nil, nil, err - } - - pr, err := planfile.Open(filename) - if err != nil { - return nil, nil, nil, err - } - - config, diags := pr.ReadConfig() - if diags.HasErrors() { - return nil, nil, nil, diags.Err() - } - - plan, err = pr.ReadPlan() - if err != nil { - return nil, nil, nil, err - } - - // Note: This has grown rather silly over the course of ongoing refactoring, - // because ContextOpts is no longer actually responsible for carrying - // any information from a plan file and instead all of the information - // lives inside the config and plan objects. We continue to return a - // silly empty ContextOpts here just to keep all of the calling tests - // working. - return &ContextOpts{}, config, plan, nil -} - -// legacyPlanComparisonString produces a string representation of the changes -// from a plan and a given state togther, as was formerly produced by the -// String method of terraform.Plan. -// -// This is here only for compatibility with existing tests that predate our -// new plan and state types, and should not be used in new tests. Instead, use -// a library like "cmp" to do a deep equality check and diff on the two -// data structures. -func legacyPlanComparisonString(state *states.State, changes *plans.Changes) string { - return fmt.Sprintf( - "DIFF:\n\n%s\n\nSTATE:\n\n%s", - legacyDiffComparisonString(changes), - state.String(), - ) -} - -// legacyDiffComparisonString produces a string representation of the changes -// from a planned changes object, as was formerly produced by the String method -// of terraform.Diff. -// -// This is here only for compatibility with existing tests that predate our -// new plan types, and should not be used in new tests. Instead, use a library -// like "cmp" to do a deep equality check and diff on the two data structures. -func legacyDiffComparisonString(changes *plans.Changes) string { - // The old string representation of a plan was grouped by module, but - // our new plan structure is not grouped in that way and so we'll need - // to preprocess it in order to produce that grouping. - type ResourceChanges struct { - Current *plans.ResourceInstanceChangeSrc - Deposed map[states.DeposedKey]*plans.ResourceInstanceChangeSrc - } - byModule := map[string]map[string]*ResourceChanges{} - resourceKeys := map[string][]string{} - var moduleKeys []string - for _, rc := range changes.Resources { - if rc.Action == plans.NoOp { - // We won't mention no-op changes here at all, since the old plan - // model we are emulating here didn't have such a concept. - continue - } - moduleKey := rc.Addr.Module.String() - if _, exists := byModule[moduleKey]; !exists { - moduleKeys = append(moduleKeys, moduleKey) - byModule[moduleKey] = make(map[string]*ResourceChanges) - } - resourceKey := rc.Addr.Resource.String() - if _, exists := byModule[moduleKey][resourceKey]; !exists { - resourceKeys[moduleKey] = append(resourceKeys[moduleKey], resourceKey) - byModule[moduleKey][resourceKey] = &ResourceChanges{ - Deposed: make(map[states.DeposedKey]*plans.ResourceInstanceChangeSrc), - } - } - - if rc.DeposedKey == states.NotDeposed { - byModule[moduleKey][resourceKey].Current = rc - } else { - byModule[moduleKey][resourceKey].Deposed[rc.DeposedKey] = rc - } - } - sort.Strings(moduleKeys) - for _, ks := range resourceKeys { - sort.Strings(ks) - } - - var buf bytes.Buffer - - for _, moduleKey := range moduleKeys { - rcs := byModule[moduleKey] - var mBuf bytes.Buffer - - for _, resourceKey := range resourceKeys[moduleKey] { - rc := rcs[resourceKey] - - crud := "UPDATE" - if rc.Current != nil { - switch rc.Current.Action { - case plans.DeleteThenCreate: - crud = "DESTROY/CREATE" - case plans.CreateThenDelete: - crud = "CREATE/DESTROY" - case plans.Delete: - crud = "DESTROY" - case plans.Create: - crud = "CREATE" - } - } else { - // We must be working on a deposed object then, in which - // case destroying is the only possible action. - crud = "DESTROY" - } - - extra := "" - if rc.Current == nil && len(rc.Deposed) > 0 { - extra = " (deposed only)" - } - - fmt.Fprintf( - &mBuf, "%s: %s%s\n", - crud, resourceKey, extra, - ) - - attrNames := map[string]bool{} - var oldAttrs map[string]string - var newAttrs map[string]string - if rc.Current != nil { - if before := rc.Current.Before; before != nil { - ty, err := before.ImpliedType() - if err == nil { - val, err := before.Decode(ty) - if err == nil { - oldAttrs = hcl2shim.FlatmapValueFromHCL2(val) - for k := range oldAttrs { - attrNames[k] = true - } - } - } - } - if after := rc.Current.After; after != nil { - ty, err := after.ImpliedType() - if err == nil { - val, err := after.Decode(ty) - if err == nil { - newAttrs = hcl2shim.FlatmapValueFromHCL2(val) - for k := range newAttrs { - attrNames[k] = true - } - } - } - } - } - if oldAttrs == nil { - oldAttrs = make(map[string]string) - } - if newAttrs == nil { - newAttrs = make(map[string]string) - } - - attrNamesOrder := make([]string, 0, len(attrNames)) - keyLen := 0 - for n := range attrNames { - attrNamesOrder = append(attrNamesOrder, n) - if len(n) > keyLen { - keyLen = len(n) - } - } - sort.Strings(attrNamesOrder) - - for _, attrK := range attrNamesOrder { - v := newAttrs[attrK] - u := oldAttrs[attrK] - - if v == hcl2shim.UnknownVariableValue { - v = "" - } - // NOTE: we don't support here because we would - // need schema to do that. Excluding sensitive values - // is now done at the UI layer, and so should not be tested - // at the core layer. - - updateMsg := "" - // TODO: Mark " (forces new resource)" in updateMsg when appropriate. - - fmt.Fprintf( - &mBuf, " %s:%s %#v => %#v%s\n", - attrK, - strings.Repeat(" ", keyLen-len(attrK)), - u, v, - updateMsg, - ) - } - } - - if moduleKey == "" { // root module - buf.Write(mBuf.Bytes()) - buf.WriteByte('\n') - continue - } - - fmt.Fprintf(&buf, "%s:\n", moduleKey) - s := bufio.NewScanner(&mBuf) - for s.Scan() { - buf.WriteString(fmt.Sprintf(" %s\n", s.Text())) - } - } - - return buf.String() -} - -// assertNoDiagnostics fails the test in progress (using t.Fatal) if the given -// diagnostics is non-empty. -func assertNoDiagnostics(t *testing.T, diags tfdiags.Diagnostics) { - t.Helper() - if len(diags) == 0 { - return - } - logDiagnostics(t, diags) - t.FailNow() -} - -// assertNoDiagnostics fails the test in progress (using t.Fatal) if the given -// diagnostics has any errors. -func assertNoErrors(t *testing.T, diags tfdiags.Diagnostics) { - t.Helper() - if !diags.HasErrors() { - return - } - logDiagnostics(t, diags) - t.FailNow() -} - -// assertDiagnosticsMatch fails the test in progress (using t.Fatal) if the -// two sets of diagnostics don't match after being normalized using the -// "ForRPC" processing step, which eliminates the specific type information -// and HCL expression information of each diagnostic. -// -// assertDiagnosticsMatch sorts the two sets of diagnostics in the usual way -// before comparing them, though diagnostics only have a partial order so that -// will not totally normalize the ordering of all diagnostics sets. -func assertDiagnosticsMatch(t *testing.T, got, want tfdiags.Diagnostics) { - got = got.ForRPC() - want = want.ForRPC() - got.Sort() - want.Sort() - if diff := cmp.Diff(want, got); diff != "" { - t.Fatalf("wrong diagnostics\n%s", diff) - } -} - -// logDiagnostics is a test helper that logs the given diagnostics to to the -// given testing.T using t.Log, in a way that is hopefully useful in debugging -// a test. It does not generate any errors or fail the test. See -// assertNoDiagnostics and assertNoErrors for more specific helpers that can -// also fail the test. -func logDiagnostics(t *testing.T, diags tfdiags.Diagnostics) { - t.Helper() - for _, diag := range diags { - desc := diag.Description() - rng := diag.Source() - - var severity string - switch diag.Severity() { - case tfdiags.Error: - severity = "ERROR" - case tfdiags.Warning: - severity = "WARN" - default: - severity = "???" // should never happen - } - - if subj := rng.Subject; subj != nil { - if desc.Detail == "" { - t.Logf("[%s@%s] %s", severity, subj.StartString(), desc.Summary) - } else { - t.Logf("[%s@%s] %s: %s", severity, subj.StartString(), desc.Summary, desc.Detail) - } - } else { - if desc.Detail == "" { - t.Logf("[%s] %s", severity, desc.Summary) - } else { - t.Logf("[%s] %s: %s", severity, desc.Summary, desc.Detail) - } - } - } -} - -const testContextRefreshModuleStr = ` -aws_instance.web: (tainted) - ID = bar - provider = provider["registry.terraform.io/hashicorp/aws"] - -module.child: - aws_instance.web: - ID = new - provider = provider["registry.terraform.io/hashicorp/aws"] -` - -const testContextRefreshOutputStr = ` -aws_instance.web: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = bar - -Outputs: - -foo = bar -` - -const testContextRefreshOutputPartialStr = ` - -` - -const testContextRefreshTaintedStr = ` -aws_instance.web: (tainted) - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] -` diff --git a/internal/terraform/context_validate.go b/internal/terraform/context_validate.go deleted file mode 100644 index aad884442a39..000000000000 --- a/internal/terraform/context_validate.go +++ /dev/null @@ -1,80 +0,0 @@ -package terraform - -import ( - "log" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" - "github.com/zclconf/go-cty/cty" -) - -// Validate performs semantic validation of a configuration, and returns -// any warnings or errors. -// -// Syntax and structural checks are performed by the configuration loader, -// and so are not repeated here. -// -// Validate considers only the configuration and so it won't catch any -// errors caused by current values in the state, or other external information -// such as root module input variables. However, the Plan function includes -// all of the same checks as Validate, in addition to the other work it does -// to consider the previous run state and the planning options. -func (c *Context) Validate(config *configs.Config) tfdiags.Diagnostics { - defer c.acquireRun("validate")() - - var diags tfdiags.Diagnostics - - moreDiags := c.checkConfigDependencies(config) - diags = diags.Append(moreDiags) - // If required dependencies are not available then we'll bail early since - // otherwise we're likely to just see a bunch of other errors related to - // incompatibilities, which could be overwhelming for the user. - if diags.HasErrors() { - return diags - } - - log.Printf("[DEBUG] Building and walking validate graph") - - // Validate is to check if the given module is valid regardless of - // input values, current state, etc. Therefore we populate all of the - // input values with unknown values of the expected type, allowing us - // to perform a type check without assuming any particular values. - varValues := make(InputValues) - for name, variable := range config.Module.Variables { - ty := variable.Type - if ty == cty.NilType { - // Can't predict the type at all, so we'll just mark it as - // cty.DynamicVal (unknown value of cty.DynamicPseudoType). - ty = cty.DynamicPseudoType - } - varValues[name] = &InputValue{ - Value: cty.UnknownVal(ty), - SourceType: ValueFromUnknown, - } - } - - graph, moreDiags := (&PlanGraphBuilder{ - Config: config, - Plugins: c.plugins, - State: states.NewState(), - RootVariableValues: varValues, - Operation: walkValidate, - }).Build(addrs.RootModuleInstance) - diags = diags.Append(moreDiags) - if moreDiags.HasErrors() { - return diags - } - - walker, walkDiags := c.walk(graph, walkValidate, &graphWalkOpts{ - Config: config, - }) - diags = diags.Append(walker.NonFatalDiagnostics) - diags = diags.Append(walkDiags) - if walkDiags.HasErrors() { - return diags - } - - return diags -} diff --git a/internal/terraform/context_validate_test.go b/internal/terraform/context_validate_test.go deleted file mode 100644 index 47e71f404f07..000000000000 --- a/internal/terraform/context_validate_test.go +++ /dev/null @@ -1,2484 +0,0 @@ -package terraform - -import ( - "errors" - "fmt" - "strings" - "testing" - - "github.com/zclconf/go-cty/cty" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/provisioners" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -func TestContext2Validate_badCount(t *testing.T) { - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{}, - }, - }, - }) - - m := testModule(t, "validate-bad-count") - c := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := c.Validate(m) - if !diags.HasErrors() { - t.Fatalf("succeeded; want error") - } -} - -func TestContext2Validate_badResource_reference(t *testing.T) { - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{}, - }, - }, - }) - - m := testModule(t, "validate-bad-resource-count") - c := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := c.Validate(m) - if !diags.HasErrors() { - t.Fatalf("succeeded; want error") - } -} - -func TestContext2Validate_badVar(t *testing.T) { - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - "num": {Type: cty.String, Optional: true}, - }, - }, - }, - }) - - m := testModule(t, "validate-bad-var") - c := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := c.Validate(m) - if !diags.HasErrors() { - t.Fatalf("succeeded; want error") - } -} - -func TestContext2Validate_varNoDefaultExplicitType(t *testing.T) { - m := testModule(t, "validate-var-no-default-explicit-type") - c, diags := NewContext(&ContextOpts{}) - if diags.HasErrors() { - t.Fatalf("unexpected NewContext errors: %s", diags.Err()) - } - - // NOTE: This test has grown idiosyncratic because originally Terraform - // would (optionally) check variables during validation, and then in - // Terraform v0.12 we switched to checking variables during NewContext, - // and now most recently we've switched to checking variables only during - // planning because root variables are a plan option. Therefore this has - // grown into a plan test rather than a validate test, but it lives on - // here in order to make it easier to navigate through that history in - // version control. - _, diags = c.Plan(m, states.NewState(), DefaultPlanOpts) - if !diags.HasErrors() { - // Error should be: The input variable "maybe_a_map" has not been assigned a value. - t.Fatalf("succeeded; want error") - } -} - -func TestContext2Validate_computedVar(t *testing.T) { - p := testProvider("aws") - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - Provider: providers.Schema{ - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "value": {Type: cty.String, Optional: true}, - }, - }, - }, - ResourceTypes: map[string]providers.Schema{ - "aws_instance": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{}, - }, - }, - }, - } - pt := testProvider("test") - pt.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - ResourceTypes: map[string]providers.Schema{ - "test_instance": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Computed: true}, - "value": {Type: cty.String, Optional: true}, - }, - }, - }, - }, - } - - m := testModule(t, "validate-computed-var") - c := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - addrs.NewDefaultProvider("test"): testProviderFuncFixed(pt), - }, - }) - - p.ValidateProviderConfigFn = func(req providers.ValidateProviderConfigRequest) (resp providers.ValidateProviderConfigResponse) { - val := req.Config.GetAttr("value") - if val.IsKnown() { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("value isn't computed")) - } - - return - } - - diags := c.Validate(m) - if diags.HasErrors() { - t.Fatalf("unexpected error: %s", diags.Err()) - } - if p.ConfigureProviderCalled { - t.Fatal("Configure should not be called for provider") - } -} - -func TestContext2Validate_computedInFunction(t *testing.T) { - p := testProvider("aws") - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - ResourceTypes: map[string]providers.Schema{ - "aws_instance": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "attr": {Type: cty.Number, Optional: true}, - }, - }, - }, - }, - DataSources: map[string]providers.Schema{ - "aws_data_source": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "optional_attr": {Type: cty.String, Optional: true}, - "computed": {Type: cty.String, Computed: true}, - }, - }, - }, - }, - } - - m := testModule(t, "validate-computed-in-function") - c := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := c.Validate(m) - if diags.HasErrors() { - t.Fatalf("unexpected error: %s", diags.Err()) - } -} - -// Test that validate allows through computed counts. We do this and allow -// them to fail during "plan" since we can't know if the computed values -// can be realized during a plan. -func TestContext2Validate_countComputed(t *testing.T) { - p := testProvider("aws") - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - ResourceTypes: map[string]providers.Schema{ - "aws_instance": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{}, - }, - }, - }, - DataSources: map[string]providers.Schema{ - "aws_data_source": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "compute": {Type: cty.String, Optional: true}, - "value": {Type: cty.String, Computed: true}, - }, - }, - }, - }, - } - - m := testModule(t, "validate-count-computed") - c := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := c.Validate(m) - if diags.HasErrors() { - t.Fatalf("unexpected error: %s", diags.Err()) - } -} - -func TestContext2Validate_countNegative(t *testing.T) { - p := testProvider("aws") - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - ResourceTypes: map[string]providers.Schema{ - "aws_instance": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{}, - }, - }, - }, - } - m := testModule(t, "validate-count-negative") - c := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := c.Validate(m) - if !diags.HasErrors() { - t.Fatalf("succeeded; want error") - } -} - -func TestContext2Validate_countVariable(t *testing.T) { - p := testProvider("aws") - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - ResourceTypes: map[string]providers.Schema{ - "aws_instance": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - }, - } - m := testModule(t, "apply-count-variable") - c := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := c.Validate(m) - if diags.HasErrors() { - t.Fatalf("unexpected error: %s", diags.Err()) - } -} - -func TestContext2Validate_countVariableNoDefault(t *testing.T) { - p := testProvider("aws") - m := testModule(t, "validate-count-variable") - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - ResourceTypes: map[string]providers.Schema{ - "aws_instance": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - }, - } - c, diags := NewContext(&ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - assertNoDiagnostics(t, diags) - - _, diags = c.Plan(m, nil, &PlanOpts{}) - if !diags.HasErrors() { - // Error should be: The input variable "foo" has not been assigned a value. - t.Fatalf("succeeded; want error") - } -} - -func TestContext2Validate_moduleBadOutput(t *testing.T) { - p := testProvider("aws") - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - ResourceTypes: map[string]providers.Schema{ - "aws_instance": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - }, - } - m := testModule(t, "validate-bad-module-output") - c := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := c.Validate(m) - if !diags.HasErrors() { - t.Fatalf("succeeded; want error") - } -} - -func TestContext2Validate_moduleGood(t *testing.T) { - p := testProvider("aws") - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - ResourceTypes: map[string]providers.Schema{ - "aws_instance": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - }, - } - m := testModule(t, "validate-good-module") - c := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := c.Validate(m) - if diags.HasErrors() { - t.Fatalf("unexpected error: %s", diags.Err()) - } -} - -func TestContext2Validate_moduleBadResource(t *testing.T) { - m := testModule(t, "validate-module-bad-rc") - p := testProvider("aws") - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - ResourceTypes: map[string]providers.Schema{ - "aws_instance": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{}, - }, - }, - }, - } - - c := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - p.ValidateResourceConfigResponse = &providers.ValidateResourceConfigResponse{ - Diagnostics: tfdiags.Diagnostics{}.Append(fmt.Errorf("bad")), - } - - diags := c.Validate(m) - if !diags.HasErrors() { - t.Fatalf("succeeded; want error") - } -} - -func TestContext2Validate_moduleDepsShouldNotCycle(t *testing.T) { - m := testModule(t, "validate-module-deps-cycle") - p := testProvider("aws") - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - ResourceTypes: map[string]providers.Schema{ - "aws_instance": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Optional: true}, - }, - }, - }, - }, - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := ctx.Validate(m) - if diags.HasErrors() { - t.Fatalf("unexpected error: %s", diags.Err()) - } -} - -func TestContext2Validate_moduleProviderVar(t *testing.T) { - m := testModule(t, "validate-module-pc-vars") - p := testProvider("aws") - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - Provider: providers.Schema{ - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - ResourceTypes: map[string]providers.Schema{ - "aws_instance": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - }, - } - - c := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - p.ValidateProviderConfigFn = func(req providers.ValidateProviderConfigRequest) (resp providers.ValidateProviderConfigResponse) { - if req.Config.GetAttr("foo").IsNull() { - resp.Diagnostics = resp.Diagnostics.Append(errors.New("foo is null")) - } - return - } - - diags := c.Validate(m) - if diags.HasErrors() { - t.Fatalf("unexpected error: %s", diags.Err()) - } -} - -func TestContext2Validate_moduleProviderInheritUnused(t *testing.T) { - m := testModule(t, "validate-module-pc-inherit-unused") - p := testProvider("aws") - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - Provider: providers.Schema{ - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - ResourceTypes: map[string]providers.Schema{ - "aws_instance": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - }, - } - - c := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - p.ValidateProviderConfigFn = func(req providers.ValidateProviderConfigRequest) (resp providers.ValidateProviderConfigResponse) { - if req.Config.GetAttr("foo").IsNull() { - resp.Diagnostics = resp.Diagnostics.Append(errors.New("foo is null")) - } - return - } - - diags := c.Validate(m) - if diags.HasErrors() { - t.Fatalf("unexpected error: %s", diags.Err()) - } -} - -func TestContext2Validate_orphans(t *testing.T) { - p := testProvider("aws") - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - ResourceTypes: map[string]providers.Schema{ - "aws_instance": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - "num": {Type: cty.String, Optional: true}, - }, - }, - }, - }, - } - - m := testModule(t, "validate-good") - - c := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - p.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse { - var diags tfdiags.Diagnostics - if req.Config.GetAttr("foo").IsNull() { - diags = diags.Append(errors.New("foo is not set")) - } - return providers.ValidateResourceConfigResponse{ - Diagnostics: diags, - } - } - - diags := c.Validate(m) - if diags.HasErrors() { - t.Fatalf("unexpected error: %s", diags.Err()) - } -} - -func TestContext2Validate_providerConfig_bad(t *testing.T) { - m := testModule(t, "validate-bad-pc") - p := testProvider("aws") - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - Provider: providers.Schema{ - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - ResourceTypes: map[string]providers.Schema{ - "aws_instance": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{}, - }, - }, - }, - } - - c := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - p.ValidateProviderConfigResponse = &providers.ValidateProviderConfigResponse{ - Diagnostics: tfdiags.Diagnostics{}.Append(fmt.Errorf("bad")), - } - - diags := c.Validate(m) - if len(diags) != 1 { - t.Fatalf("wrong number of diagnostics %d; want %d", len(diags), 1) - } - if !strings.Contains(diags.Err().Error(), "bad") { - t.Fatalf("bad: %s", diags.Err().Error()) - } -} - -func TestContext2Validate_providerConfig_skippedEmpty(t *testing.T) { - m := testModule(t, "validate-skipped-pc-empty") - p := testProvider("aws") - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - Provider: providers.Schema{ - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - ResourceTypes: map[string]providers.Schema{ - "aws_instance": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{}, - }, - }, - }, - } - - c := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - p.ValidateProviderConfigResponse = &providers.ValidateProviderConfigResponse{ - Diagnostics: tfdiags.Diagnostics{}.Append(fmt.Errorf("should not be called")), - } - - diags := c.Validate(m) - if diags.HasErrors() { - t.Fatalf("unexpected error: %s", diags.Err()) - } -} - -func TestContext2Validate_providerConfig_good(t *testing.T) { - m := testModule(t, "validate-bad-pc") - p := testProvider("aws") - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - Provider: providers.Schema{ - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - ResourceTypes: map[string]providers.Schema{ - "aws_instance": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{}, - }, - }, - }, - } - - c := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := c.Validate(m) - if diags.HasErrors() { - t.Fatalf("unexpected error: %s", diags.Err()) - } -} - -// In this test there is a mismatch between the provider's fqn (hashicorp/test) -// and it's local name set in required_providers (arbitrary). -func TestContext2Validate_requiredProviderConfig(t *testing.T) { - m := testModule(t, "validate-required-provider-config") - p := testProvider("aws") - - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - Provider: providers.Schema{ - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "required_attribute": {Type: cty.String, Required: true}, - }, - }, - }, - ResourceTypes: map[string]providers.Schema{ - "aws_instance": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{}, - }, - }, - }, - } - - c := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := c.Validate(m) - if diags.HasErrors() { - t.Fatalf("unexpected error: %s", diags.Err()) - } -} - -func TestContext2Validate_provisionerConfig_bad(t *testing.T) { - m := testModule(t, "validate-bad-prov-conf") - p := testProvider("aws") - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - ResourceTypes: map[string]providers.Schema{ - "aws_instance": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - }, - } - - pr := simpleMockProvisioner() - - c := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Provisioners: map[string]provisioners.Factory{ - "shell": testProvisionerFuncFixed(pr), - }, - }) - - p.ValidateProviderConfigResponse = &providers.ValidateProviderConfigResponse{ - Diagnostics: tfdiags.Diagnostics{}.Append(fmt.Errorf("bad")), - } - - diags := c.Validate(m) - if !diags.HasErrors() { - t.Fatalf("succeeded; want error") - } -} - -func TestContext2Validate_badResourceConnection(t *testing.T) { - m := testModule(t, "validate-bad-resource-connection") - p := testProvider("aws") - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - ResourceTypes: map[string]providers.Schema{ - "aws_instance": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - }, - } - - pr := simpleMockProvisioner() - - c := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Provisioners: map[string]provisioners.Factory{ - "shell": testProvisionerFuncFixed(pr), - }, - }) - - diags := c.Validate(m) - t.Log(diags.Err()) - if !diags.HasErrors() { - t.Fatalf("succeeded; want error") - } -} - -func TestContext2Validate_badProvisionerConnection(t *testing.T) { - m := testModule(t, "validate-bad-prov-connection") - p := testProvider("aws") - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - ResourceTypes: map[string]providers.Schema{ - "aws_instance": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - }, - } - - pr := simpleMockProvisioner() - - c := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Provisioners: map[string]provisioners.Factory{ - "shell": testProvisionerFuncFixed(pr), - }, - }) - - diags := c.Validate(m) - t.Log(diags.Err()) - if !diags.HasErrors() { - t.Fatalf("succeeded; want error") - } -} - -func TestContext2Validate_provisionerConfig_good(t *testing.T) { - m := testModule(t, "validate-bad-prov-conf") - p := testProvider("aws") - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - Provider: providers.Schema{ - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - ResourceTypes: map[string]providers.Schema{ - "aws_instance": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - }, - } - - pr := simpleMockProvisioner() - pr.ValidateProvisionerConfigFn = func(req provisioners.ValidateProvisionerConfigRequest) provisioners.ValidateProvisionerConfigResponse { - var diags tfdiags.Diagnostics - if req.Config.GetAttr("test_string").IsNull() { - diags = diags.Append(errors.New("test_string is not set")) - } - return provisioners.ValidateProvisionerConfigResponse{ - Diagnostics: diags, - } - } - - c := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Provisioners: map[string]provisioners.Factory{ - "shell": testProvisionerFuncFixed(pr), - }, - }) - - diags := c.Validate(m) - if diags.HasErrors() { - t.Fatalf("unexpected error: %s", diags.Err()) - } -} - -func TestContext2Validate_requiredVar(t *testing.T) { - m := testModule(t, "validate-required-var") - p := testProvider("aws") - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - ResourceTypes: map[string]providers.Schema{ - "aws_instance": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "ami": {Type: cty.String, Optional: true}, - }, - }, - }, - }, - } - c, diags := NewContext(&ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - assertNoDiagnostics(t, diags) - - // NOTE: This test has grown idiosyncratic because originally Terraform - // would (optionally) check variables during validation, and then in - // Terraform v0.12 we switched to checking variables during NewContext, - // and now most recently we've switched to checking variables only during - // planning because root variables are a plan option. Therefore this has - // grown into a plan test rather than a validate test, but it lives on - // here in order to make it easier to navigate through that history in - // version control. - _, diags = c.Plan(m, states.NewState(), DefaultPlanOpts) - if !diags.HasErrors() { - // Error should be: The input variable "foo" has not been assigned a value. - t.Fatalf("succeeded; want error") - } -} - -func TestContext2Validate_resourceConfig_bad(t *testing.T) { - m := testModule(t, "validate-bad-rc") - p := testProvider("aws") - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - ResourceTypes: map[string]providers.Schema{ - "aws_instance": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - }, - } - c := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - p.ValidateResourceConfigResponse = &providers.ValidateResourceConfigResponse{ - Diagnostics: tfdiags.Diagnostics{}.Append(fmt.Errorf("bad")), - } - - diags := c.Validate(m) - if !diags.HasErrors() { - t.Fatalf("succeeded; want error") - } -} - -func TestContext2Validate_resourceConfig_good(t *testing.T) { - m := testModule(t, "validate-bad-rc") - p := testProvider("aws") - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - ResourceTypes: map[string]providers.Schema{ - "aws_instance": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - }, - } - c := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := c.Validate(m) - if diags.HasErrors() { - t.Fatalf("unexpected error: %s", diags.Err()) - } -} - -func TestContext2Validate_tainted(t *testing.T) { - p := testProvider("aws") - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - ResourceTypes: map[string]providers.Schema{ - "aws_instance": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - "num": {Type: cty.String, Optional: true}, - }, - }, - }, - }, - } - - m := testModule(t, "validate-good") - c := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - p.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse { - var diags tfdiags.Diagnostics - if req.Config.GetAttr("foo").IsNull() { - diags = diags.Append(errors.New("foo is not set")) - } - return providers.ValidateResourceConfigResponse{ - Diagnostics: diags, - } - } - - diags := c.Validate(m) - if diags.HasErrors() { - t.Fatalf("unexpected error: %s", diags.Err()) - } -} - -func TestContext2Validate_targetedDestroy(t *testing.T) { - m := testModule(t, "validate-targeted") - p := testProvider("aws") - pr := simpleMockProvisioner() - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - ResourceTypes: map[string]providers.Schema{ - "aws_instance": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - "num": {Type: cty.String, Optional: true}, - }, - }, - }, - }, - } - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - testSetResourceInstanceCurrent(root, "aws_instance.foo", `{"id":"i-bcd345"}`, `provider["registry.terraform.io/hashicorp/aws"]`) - testSetResourceInstanceCurrent(root, "aws_instance.bar", `{"id":"i-abc123"}`, `provider["registry.terraform.io/hashicorp/aws"]`) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Provisioners: map[string]provisioners.Factory{ - "shell": testProvisionerFuncFixed(pr), - }, - }) - - diags := ctx.Validate(m) - if diags.HasErrors() { - t.Fatalf("unexpected error: %s", diags.Err()) - } -} - -func TestContext2Validate_varRefUnknown(t *testing.T) { - m := testModule(t, "validate-variable-ref") - p := testProvider("aws") - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - ResourceTypes: map[string]providers.Schema{ - "aws_instance": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - }, - } - c := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - var value cty.Value - p.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse { - value = req.Config.GetAttr("foo") - return providers.ValidateResourceConfigResponse{} - } - - c.Validate(m) - - // Input variables are always unknown during the validate walk, because - // we're checking for validity of all possible input values. Validity - // against specific input values is checked during the plan walk. - if !value.RawEquals(cty.UnknownVal(cty.String)) { - t.Fatalf("bad: %#v", value) - } -} - -// Module variables weren't being interpolated during Validate phase. -// related to https://github.com/hashicorp/terraform/issues/5322 -func TestContext2Validate_interpolateVar(t *testing.T) { - input := new(MockUIInput) - - m := testModule(t, "input-interpolate-var") - p := testProvider("null") - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - ResourceTypes: map[string]providers.Schema{ - "template_file": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "template": {Type: cty.String, Optional: true}, - }, - }, - }, - }, - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("template"): testProviderFuncFixed(p), - }, - UIInput: input, - }) - - diags := ctx.Validate(m) - if diags.HasErrors() { - t.Fatalf("unexpected error: %s", diags.Err()) - } -} - -// When module vars reference something that is actually computed, this -// shouldn't cause validation to fail. -func TestContext2Validate_interpolateComputedModuleVarDef(t *testing.T) { - input := new(MockUIInput) - - m := testModule(t, "validate-computed-module-var-ref") - p := testProvider("aws") - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - ResourceTypes: map[string]providers.Schema{ - "aws_instance": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "attr": {Type: cty.String, Optional: true}, - }, - }, - }, - }, - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - UIInput: input, - }) - - diags := ctx.Validate(m) - if diags.HasErrors() { - t.Fatalf("unexpected error: %s", diags.Err()) - } -} - -// Computed values are lost when a map is output from a module -func TestContext2Validate_interpolateMap(t *testing.T) { - input := new(MockUIInput) - - m := testModule(t, "issue-9549") - p := testProvider("template") - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("template"): testProviderFuncFixed(p), - }, - UIInput: input, - }) - - diags := ctx.Validate(m) - if diags.HasErrors() { - t.Fatalf("unexpected error: %s", diags.Err()) - } -} - -func TestContext2Validate_varSensitive(t *testing.T) { - // Smoke test through validate where a variable has sensitive applied - m := testModuleInline(t, map[string]string{ - "main.tf": ` -variable "foo" { - default = "xyz" - sensitive = true -} - -variable "bar" { - sensitive = true -} - -data "aws_data_source" "bar" { - foo = var.bar -} - -resource "aws_instance" "foo" { - foo = var.foo -} -`, - }) - - p := testProvider("aws") - p.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse { - // Providers receive unmarked values - if got, want := req.Config.GetAttr("foo"), cty.UnknownVal(cty.String); !got.RawEquals(want) { - t.Fatalf("wrong value for foo\ngot: %#v\nwant: %#v", got, want) - } - return providers.ValidateResourceConfigResponse{} - } - p.ValidateDataResourceConfigFn = func(req providers.ValidateDataResourceConfigRequest) (resp providers.ValidateDataResourceConfigResponse) { - if got, want := req.Config.GetAttr("foo"), cty.UnknownVal(cty.String); !got.RawEquals(want) { - t.Fatalf("wrong value for foo\ngot: %#v\nwant: %#v", got, want) - } - return providers.ValidateDataResourceConfigResponse{} - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := ctx.Validate(m) - if diags.HasErrors() { - t.Fatal(diags.Err()) - } - - if !p.ValidateResourceConfigCalled { - t.Fatal("expected ValidateResourceConfigFn to be called") - } - - if !p.ValidateDataResourceConfigCalled { - t.Fatal("expected ValidateDataSourceConfigFn to be called") - } -} - -func TestContext2Validate_invalidOutput(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -data "aws_data_source" "name" {} - -output "out" { - value = "${data.aws_data_source.name.missing}" -}`, - }) - - p := testProvider("aws") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := ctx.Validate(m) - if !diags.HasErrors() { - t.Fatal("succeeded; want errors") - } - // Should get this error: - // Unsupported attribute: This object does not have an attribute named "missing" - if got, want := diags.Err().Error(), "Unsupported attribute"; !strings.Contains(got, want) { - t.Fatalf("wrong error:\ngot: %s\nwant: message containing %q", got, want) - } -} - -func TestContext2Validate_invalidModuleOutput(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "child/main.tf": ` -data "aws_data_source" "name" {} - -output "out" { - value = "${data.aws_data_source.name.missing}" -}`, - "main.tf": ` -module "child" { - source = "./child" -} - -resource "aws_instance" "foo" { - foo = "${module.child.out}" -}`, - }) - - p := testProvider("aws") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := ctx.Validate(m) - if !diags.HasErrors() { - t.Fatal("succeeded; want errors") - } - // Should get this error: - // Unsupported attribute: This object does not have an attribute named "missing" - if got, want := diags.Err().Error(), "Unsupported attribute"; !strings.Contains(got, want) { - t.Fatalf("wrong error:\ngot: %s\nwant: message containing %q", got, want) - } -} - -func TestContext2Validate_sensitiveRootModuleOutput(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "child/main.tf": ` -variable "foo" { - default = "xyz" - sensitive = true -} - -output "out" { - value = var.foo -}`, - "main.tf": ` -module "child" { - source = "./child" -} - -output "root" { - value = module.child.out - sensitive = true -}`, - }) - - ctx := testContext2(t, &ContextOpts{}) - - diags := ctx.Validate(m) - if diags.HasErrors() { - t.Fatal(diags.Err()) - } -} - -func TestContext2Validate_legacyResourceCount(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "aws_instance" "test" {} - -output "out" { - value = aws_instance.test.count -}`, - }) - - p := testProvider("aws") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := ctx.Validate(m) - if !diags.HasErrors() { - t.Fatal("succeeded; want errors") - } - // Should get this error: - // Invalid resource count attribute: The special "count" attribute is no longer supported after Terraform v0.12. Instead, use length(aws_instance.test) to count resource instances. - if got, want := diags.Err().Error(), "Invalid resource count attribute:"; !strings.Contains(got, want) { - t.Fatalf("wrong error:\ngot: %s\nwant: message containing %q", got, want) - } -} - -func TestContext2Validate_invalidModuleRef(t *testing.T) { - // This test is verifying that we properly validate and report on references - // to modules that are not declared, since we were missing some validation - // here in early 0.12.0 alphas that led to a panic. - m := testModuleInline(t, map[string]string{ - "main.tf": ` -output "out" { - # Intentionally referencing undeclared module to ensure error - value = module.foo -}`, - }) - - p := testProvider("aws") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := ctx.Validate(m) - if !diags.HasErrors() { - t.Fatal("succeeded; want errors") - } - // Should get this error: - // Reference to undeclared module: No module call named "foo" is declared in the root module. - if got, want := diags.Err().Error(), "Reference to undeclared module:"; !strings.Contains(got, want) { - t.Fatalf("wrong error:\ngot: %s\nwant: message containing %q", got, want) - } -} - -func TestContext2Validate_invalidModuleOutputRef(t *testing.T) { - // This test is verifying that we properly validate and report on references - // to modules that are not declared, since we were missing some validation - // here in early 0.12.0 alphas that led to a panic. - m := testModuleInline(t, map[string]string{ - "main.tf": ` -output "out" { - # Intentionally referencing undeclared module to ensure error - value = module.foo.bar -}`, - }) - - p := testProvider("aws") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := ctx.Validate(m) - if !diags.HasErrors() { - t.Fatal("succeeded; want errors") - } - // Should get this error: - // Reference to undeclared module: No module call named "foo" is declared in the root module. - if got, want := diags.Err().Error(), "Reference to undeclared module:"; !strings.Contains(got, want) { - t.Fatalf("wrong error:\ngot: %s\nwant: message containing %q", got, want) - } -} - -func TestContext2Validate_invalidDependsOnResourceRef(t *testing.T) { - // This test is verifying that we raise an error if depends_on - // refers to something that doesn't exist in configuration. - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "test_instance" "bar" { - depends_on = [test_resource.nonexistant] -} -`, - }) - - p := testProvider("test") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - diags := ctx.Validate(m) - if !diags.HasErrors() { - t.Fatal("succeeded; want errors") - } - // Should get this error: - // Reference to undeclared module: No module call named "foo" is declared in the root module. - if got, want := diags.Err().Error(), "Reference to undeclared resource:"; !strings.Contains(got, want) { - t.Fatalf("wrong error:\ngot: %s\nwant: message containing %q", got, want) - } -} - -func TestContext2Validate_invalidResourceIgnoreChanges(t *testing.T) { - // This test is verifying that we raise an error if ignore_changes - // refers to something that can be statically detected as not conforming - // to the resource type schema. - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "test_instance" "bar" { - lifecycle { - ignore_changes = [does_not_exist_in_schema] - } -} -`, - }) - - p := testProvider("test") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - diags := ctx.Validate(m) - if !diags.HasErrors() { - t.Fatal("succeeded; want errors") - } - // Should get this error: - // Reference to undeclared module: No module call named "foo" is declared in the root module. - if got, want := diags.Err().Error(), `no argument, nested block, or exported attribute named "does_not_exist_in_schema"`; !strings.Contains(got, want) { - t.Fatalf("wrong error:\ngot: %s\nwant: message containing %q", got, want) - } -} - -func TestContext2Validate_variableCustomValidationsFail(t *testing.T) { - // This test is for custom validation rules associated with root module - // variables, and specifically that we handle the situation where the - // given value is invalid in a child module. - m := testModule(t, "validate-variable-custom-validations-child") - - p := testProvider("test") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - diags := ctx.Validate(m) - if !diags.HasErrors() { - t.Fatal("succeeded; want errors") - } - if got, want := diags.Err().Error(), `Invalid value for variable: Value must not be "nope".`; !strings.Contains(got, want) { - t.Fatalf("wrong error:\ngot: %s\nwant: message containing %q", got, want) - } -} - -func TestContext2Validate_variableCustomValidationsRoot(t *testing.T) { - // This test is for custom validation rules associated with root module - // variables, and specifically that we handle the situation where their - // values are unknown during validation, skipping the validation check - // altogether. (Root module variables are never known during validation.) - m := testModuleInline(t, map[string]string{ - "main.tf": ` -variable "test" { - type = string - - validation { - condition = var.test != "nope" - error_message = "Value must not be \"nope\"." - } -} -`, - }) - - p := testProvider("test") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - diags := ctx.Validate(m) - if diags.HasErrors() { - t.Fatalf("unexpected error\ngot: %s", diags.Err().Error()) - } -} - -func TestContext2Validate_expandModules(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -module "mod1" { - for_each = toset(["a", "b"]) - source = "./mod" -} - -module "mod2" { - for_each = module.mod1 - source = "./mod" - input = module.mod1["a"].out -} - -module "mod3" { - count = length(module.mod2) - source = "./mod" -} -`, - "mod/main.tf": ` -resource "aws_instance" "foo" { -} - -output "out" { - value = 1 -} - -variable "input" { - type = number - default = 0 -} - -module "nested" { - count = 2 - source = "./nested" - input = count.index -} -`, - "mod/nested/main.tf": ` -variable "input" { -} - -resource "aws_instance" "foo" { - count = var.input -} -`, - }) - - p := testProvider("aws") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := ctx.Validate(m) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } -} - -func TestContext2Validate_expandModulesInvalidCount(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -module "mod1" { - count = -1 - source = "./mod" -} -`, - "mod/main.tf": ` -resource "aws_instance" "foo" { -} -`, - }) - - p := testProvider("aws") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := ctx.Validate(m) - if !diags.HasErrors() { - t.Fatal("succeeded; want errors") - } - if got, want := diags.Err().Error(), `Invalid count argument`; !strings.Contains(got, want) { - t.Fatalf("wrong error:\ngot: %s\nwant: message containing %q", got, want) - } -} - -func TestContext2Validate_expandModulesInvalidForEach(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -module "mod1" { - for_each = ["a", "b"] - source = "./mod" -} -`, - "mod/main.tf": ` -resource "aws_instance" "foo" { -} -`, - }) - - p := testProvider("aws") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := ctx.Validate(m) - if !diags.HasErrors() { - t.Fatal("succeeded; want errors") - } - if got, want := diags.Err().Error(), `Invalid for_each argument`; !strings.Contains(got, want) { - t.Fatalf("wrong error:\ngot: %s\nwant: message containing %q", got, want) - } -} - -func TestContext2Validate_expandMultipleNestedModules(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -module "modA" { - for_each = { - first = "m" - second = "n" - } - source = "./modA" -} -`, - "modA/main.tf": ` -locals { - m = { - first = "m" - second = "n" - } -} - -module "modB" { - for_each = local.m - source = "./modB" - y = each.value -} - -module "modC" { - for_each = local.m - source = "./modC" - x = module.modB[each.key].out - y = module.modB[each.key].out -} - -`, - "modA/modB/main.tf": ` -variable "y" { - type = string -} - -resource "aws_instance" "foo" { - foo = var.y -} - -output "out" { - value = aws_instance.foo.id -} -`, - "modA/modC/main.tf": ` -variable "x" { - type = string -} - -variable "y" { - type = string -} - -resource "aws_instance" "foo" { - foo = var.x -} - -output "out" { - value = var.y -} -`, - }) - - p := testProvider("aws") - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := ctx.Validate(m) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } -} - -func TestContext2Validate_invalidModuleDependsOn(t *testing.T) { - // validate module and output depends_on - m := testModuleInline(t, map[string]string{ - "main.tf": ` -module "mod1" { - source = "./mod" - depends_on = [resource_foo.bar.baz] -} - -module "mod2" { - source = "./mod" - depends_on = [resource_foo.bar.baz] -} -`, - "mod/main.tf": ` -output "out" { - value = "foo" -} -`, - }) - - diags := testContext2(t, &ContextOpts{}).Validate(m) - if !diags.HasErrors() { - t.Fatal("succeeded; want errors") - } - - if len(diags) != 2 { - t.Fatalf("wanted 2 diagnostic errors, got %q", diags) - } - - for _, d := range diags { - des := d.Description().Summary - if !strings.Contains(des, "Invalid depends_on reference") { - t.Fatalf(`expected "Invalid depends_on reference", got %q`, des) - } - } -} - -func TestContext2Validate_invalidOutputDependsOn(t *testing.T) { - // validate module and output depends_on - m := testModuleInline(t, map[string]string{ - "main.tf": ` -module "mod1" { - source = "./mod" -} - -output "out" { - value = "bar" - depends_on = [resource_foo.bar.baz] -} -`, - "mod/main.tf": ` -output "out" { - value = "bar" - depends_on = [resource_foo.bar.baz] -} -`, - }) - - diags := testContext2(t, &ContextOpts{}).Validate(m) - if !diags.HasErrors() { - t.Fatal("succeeded; want errors") - } - - if len(diags) != 2 { - t.Fatalf("wanted 2 diagnostic errors, got %q", diags) - } - - for _, d := range diags { - des := d.Description().Summary - if !strings.Contains(des, "Invalid depends_on reference") { - t.Fatalf(`expected "Invalid depends_on reference", got %q`, des) - } - } -} - -func TestContext2Validate_rpcDiagnostics(t *testing.T) { - // validate module and output depends_on - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "test_instance" "a" { -} -`, - }) - - p := testProvider("test") - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - ResourceTypes: map[string]providers.Schema{ - "test_instance": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Computed: true}, - }, - }, - }, - }, - } - - p.ValidateResourceConfigResponse = &providers.ValidateResourceConfigResponse{ - Diagnostics: tfdiags.Diagnostics(nil).Append(tfdiags.SimpleWarning("don't frobble")), - } - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - diags := ctx.Validate(m) - if diags.HasErrors() { - t.Fatal(diags.Err()) - } - - if len(diags) == 0 { - t.Fatal("expected warnings") - } - - for _, d := range diags { - des := d.Description().Summary - if !strings.Contains(des, "frobble") { - t.Fatalf(`expected frobble, got %q`, des) - } - } -} - -func TestContext2Validate_sensitiveProvisionerConfig(t *testing.T) { - m := testModule(t, "validate-sensitive-provisioner-config") - p := testProvider("aws") - p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ - ResourceTypes: map[string]providers.Schema{ - "aws_instance": { - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - }, - } - - pr := simpleMockProvisioner() - - c := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - Provisioners: map[string]provisioners.Factory{ - "test": testProvisionerFuncFixed(pr), - }, - }) - - pr.ValidateProvisionerConfigFn = func(r provisioners.ValidateProvisionerConfigRequest) provisioners.ValidateProvisionerConfigResponse { - if r.Config.ContainsMarked() { - t.Errorf("provisioner config contains marked values") - } - return pr.ValidateProvisionerConfigResponse - } - - diags := c.Validate(m) - if diags.HasErrors() { - t.Fatalf("unexpected error: %s", diags.Err()) - } - if !pr.ValidateProvisionerConfigCalled { - t.Fatal("ValidateProvisionerConfig not called") - } -} - -func TestContext2Plan_validateMinMaxDynamicBlock(t *testing.T) { - p := new(MockProvider) - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test_instance": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - "things": { - Type: cty.List(cty.String), - Computed: true, - }, - }, - BlockTypes: map[string]*configschema.NestedBlock{ - "foo": { - Block: configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "bar": {Type: cty.String, Optional: true}, - }, - }, - Nesting: configschema.NestingList, - MinItems: 2, - MaxItems: 3, - }, - }, - }, - }, - }) - - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "test_instance" "a" { - // MinItems 2 - foo { - bar = "a" - } - foo { - bar = "b" - } -} - -resource "test_instance" "b" { - // one dymamic block can satisfy MinItems of 2 - dynamic "foo" { - for_each = test_instance.a.things - content { - bar = foo.value - } - } -} - -resource "test_instance" "c" { - // we may have more than MaxItems dynamic blocks when they are unknown - foo { - bar = "b" - } - dynamic "foo" { - for_each = test_instance.a.things - content { - bar = foo.value - } - } - dynamic "foo" { - for_each = test_instance.a.things - content { - bar = "${foo.value}-2" - } - } - dynamic "foo" { - for_each = test_instance.b.things - content { - bar = foo.value - } - } -} -`}) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - diags := ctx.Validate(m) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } -} - -func TestContext2Validate_passInheritedProvider(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` -terraform { - required_providers { - test = { - source = "hashicorp/test" - } - } -} - -module "first" { - source = "./first" - providers = { - test = test - } -} -`, - - // This module does not define a config for the test provider, but we - // should be able to pass whatever the implied config is to a child - // module. - "first/main.tf": ` -terraform { - required_providers { - test = { - source = "hashicorp/test" - } - } -} - -module "second" { - source = "./second" - providers = { - test.alias = test - } -}`, - - "first/second/main.tf": ` -terraform { - required_providers { - test = { - source = "hashicorp/test" - configuration_aliases = [test.alias] - } - } -} - -resource "test_object" "t" { - provider = test.alias -} -`, - }) - - p := simpleMockProvider() - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - diags := ctx.Validate(m) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } -} - -func TestContext2Plan_lookupMismatchedObjectTypes(t *testing.T) { - p := new(MockProvider) - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test_instance": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - "things": { - Type: cty.List(cty.String), - Optional: true, - }, - }, - }, - }, - }) - - m := testModuleInline(t, map[string]string{ - "main.tf": ` -variable "items" { - type = list(string) - default = [] -} - -resource "test_instance" "a" { - for_each = length(var.items) > 0 ? { default = {} } : {} -} - -output "out" { - // Strictly speaking, this expression is incorrect because the map element - // type is a different type from the default value, and the lookup - // implementation expects to be able to convert the default to match the - // element type. - // There are two reasons this works which we need to maintain for - // compatibility. First during validation the 'test_instance.a' expression - // only returns a dynamic value, preventing any type comparison. Later during - // plan and apply 'test_instance.a' is an object and not a map, and the - // lookup implementation skips the type comparison when the keys are known - // statically. - value = lookup(test_instance.a, "default", { id = null })["id"] -} -`}) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), - }, - }) - - diags := ctx.Validate(m) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } -} - -func TestContext2Validate_nonNullableVariableDefaultValidation(t *testing.T) { - m := testModuleInline(t, map[string]string{ - "main.tf": ` - module "first" { - source = "./mod" - input = null - } - `, - - "mod/main.tf": ` - variable "input" { - type = string - default = "default" - nullable = false - - // Validation expressions should receive the default with nullable=false and - // a null input. - validation { - condition = var.input != null - error_message = "Input cannot be null!" - } - } - `, - }) - - ctx := testContext2(t, &ContextOpts{}) - - diags := ctx.Validate(m) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } -} - -func TestContext2Validate_precondition_good(t *testing.T) { - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - }) - m := testModuleInline(t, map[string]string{ - "main.tf": ` -variable "input" { - type = string - default = "foo" -} - -resource "aws_instance" "test" { - foo = var.input - - lifecycle { - precondition { - condition = length(var.input) > 0 - error_message = "Input cannot be empty." - } - } -} - `, - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := ctx.Validate(m) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } -} - -func TestContext2Validate_precondition_badCondition(t *testing.T) { - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - }) - m := testModuleInline(t, map[string]string{ - "main.tf": ` -variable "input" { - type = string - default = "foo" -} - -resource "aws_instance" "test" { - foo = var.input - - lifecycle { - precondition { - condition = length(one(var.input)) == 1 - error_message = "You can't do that." - } - } -} - `, - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := ctx.Validate(m) - if !diags.HasErrors() { - t.Fatalf("succeeded; want error") - } - if got, want := diags.Err().Error(), "Invalid function argument"; !strings.Contains(got, want) { - t.Errorf("unexpected error.\ngot: %s\nshould contain: %q", got, want) - } -} - -func TestContext2Validate_precondition_badErrorMessage(t *testing.T) { - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - }) - m := testModuleInline(t, map[string]string{ - "main.tf": ` -variable "input" { - type = string - default = "foo" -} - -resource "aws_instance" "test" { - foo = var.input - - lifecycle { - precondition { - condition = var.input != "foo" - error_message = "This is a bad use of a function: ${one(var.input)}." - } - } -} - `, - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := ctx.Validate(m) - if !diags.HasErrors() { - t.Fatalf("succeeded; want error") - } - if got, want := diags.Err().Error(), "Invalid function argument"; !strings.Contains(got, want) { - t.Errorf("unexpected error.\ngot: %s\nshould contain: %q", got, want) - } -} - -func TestContext2Validate_postcondition_good(t *testing.T) { - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - }) - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "aws_instance" "test" { - foo = "foo" - - lifecycle { - postcondition { - condition = length(self.foo) > 0 - error_message = "Input cannot be empty." - } - } -} - `, - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := ctx.Validate(m) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } -} - -func TestContext2Validate_postcondition_badCondition(t *testing.T) { - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - }) - // This postcondition's condition expression does not refer to self, which - // is unrealistic. This is because at the time of writing the test, self is - // always an unknown value of dynamic type during validation. As a result, - // validation of conditions which refer to resource arguments is not - // possible until plan time. For now we exercise the code by referring to - // an input variable. - m := testModuleInline(t, map[string]string{ - "main.tf": ` -variable "input" { - type = string - default = "foo" -} - -resource "aws_instance" "test" { - foo = var.input - - lifecycle { - postcondition { - condition = length(one(var.input)) == 1 - error_message = "You can't do that." - } - } -} - `, - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := ctx.Validate(m) - if !diags.HasErrors() { - t.Fatalf("succeeded; want error") - } - if got, want := diags.Err().Error(), "Invalid function argument"; !strings.Contains(got, want) { - t.Errorf("unexpected error.\ngot: %s\nshould contain: %q", got, want) - } -} - -func TestContext2Validate_postcondition_badErrorMessage(t *testing.T) { - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - }) - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "aws_instance" "test" { - foo = "foo" - - lifecycle { - postcondition { - condition = self.foo != "foo" - error_message = "This is a bad use of a function: ${one("foo")}." - } - } -} - `, - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := ctx.Validate(m) - if !diags.HasErrors() { - t.Fatalf("succeeded; want error") - } - if got, want := diags.Err().Error(), "Invalid function argument"; !strings.Contains(got, want) { - t.Errorf("unexpected error.\ngot: %s\nshould contain: %q", got, want) - } -} - -func TestContext2Validate_precondition_count(t *testing.T) { - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - }) - m := testModuleInline(t, map[string]string{ - "main.tf": ` -locals { - foos = ["bar", "baz"] -} - -resource "aws_instance" "test" { - count = 3 - foo = local.foos[count.index] - - lifecycle { - precondition { - condition = count.index < length(local.foos) - error_message = "Insufficient foos." - } - } -} - `, - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := ctx.Validate(m) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } -} - -func TestContext2Validate_postcondition_forEach(t *testing.T) { - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - }) - m := testModuleInline(t, map[string]string{ - "main.tf": ` -locals { - foos = toset(["bar", "baz", "boop"]) -} - -resource "aws_instance" "test" { - for_each = local.foos - foo = "foo" - - lifecycle { - postcondition { - condition = length(each.value) == 3 - error_message = "Short foo required, not \"${each.key}\"." - } - } -} - `, - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := ctx.Validate(m) - if diags.HasErrors() { - t.Fatal(diags.ErrWithWarnings()) - } -} - -func TestContext2Validate_deprecatedAttr(t *testing.T) { - p := testProvider("aws") - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true, Deprecated: true}, - }, - }, - }, - }) - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "aws_instance" "test" { -} -locals { - deprecated = aws_instance.test.foo -} - - `, - }) - - ctx := testContext2(t, &ContextOpts{ - Providers: map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), - }, - }) - - diags := ctx.Validate(m) - warn := diags.ErrWithWarnings().Error() - if !strings.Contains(warn, `The attribute "foo" is deprecated`) { - t.Fatalf("expected deprecated warning, got: %q\n", warn) - } -} diff --git a/internal/terraform/context_walk.go b/internal/terraform/context_walk.go deleted file mode 100644 index 523fa738541f..000000000000 --- a/internal/terraform/context_walk.go +++ /dev/null @@ -1,144 +0,0 @@ -package terraform - -import ( - "log" - - "github.com/hashicorp/terraform/internal/checks" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/instances" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/refactoring" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -// graphWalkOpts captures some transient values we use (and possibly mutate) -// during a graph walk. -// -// The way these options get used unfortunately varies between the different -// walkOperation types. This is a historical design wart that dates back to -// us using the same graph structure for all operations; hopefully we'll -// make the necessary differences between the walk types more explicit someday. -type graphWalkOpts struct { - InputState *states.State - Changes *plans.Changes - Config *configs.Config - - // PlanTimeCheckResults should be populated during the apply phase with - // the snapshot of check results that was generated during the plan step. - // - // This then propagates the decisions about which checkable objects exist - // from the plan phase into the apply phase without having to re-compute - // the module and resource expansion. - PlanTimeCheckResults *states.CheckResults - - MoveResults refactoring.MoveResults -} - -func (c *Context) walk(graph *Graph, operation walkOperation, opts *graphWalkOpts) (*ContextGraphWalker, tfdiags.Diagnostics) { - log.Printf("[DEBUG] Starting graph walk: %s", operation.String()) - - walker := c.graphWalker(operation, opts) - - // Watch for a stop so we can call the provider Stop() API. - watchStop, watchWait := c.watchStop(walker) - - // Walk the real graph, this will block until it completes - diags := graph.Walk(walker) - - // Close the channel so the watcher stops, and wait for it to return. - close(watchStop) - <-watchWait - - return walker, diags -} - -func (c *Context) graphWalker(operation walkOperation, opts *graphWalkOpts) *ContextGraphWalker { - var state *states.SyncState - var refreshState *states.SyncState - var prevRunState *states.SyncState - - // NOTE: None of the SyncState objects must directly wrap opts.InputState, - // because we use those to mutate the state object and opts.InputState - // belongs to our caller and thus we must treat it as immutable. - // - // To account for that, most of our SyncState values created below end up - // wrapping a _deep copy_ of opts.InputState instead. - inputState := opts.InputState - if inputState == nil { - // Lots of callers use nil to represent the "empty" case where we've - // not run Apply yet, so we tolerate that. - inputState = states.NewState() - } - - switch operation { - case walkValidate: - // validate should not use any state - state = states.NewState().SyncWrapper() - - // validate currently uses the plan graph, so we have to populate the - // refreshState and the prevRunState. - refreshState = states.NewState().SyncWrapper() - prevRunState = states.NewState().SyncWrapper() - - case walkPlan, walkPlanDestroy, walkImport: - state = inputState.DeepCopy().SyncWrapper() - refreshState = inputState.DeepCopy().SyncWrapper() - prevRunState = inputState.DeepCopy().SyncWrapper() - - // For both of our new states we'll discard the previous run's - // check results, since we can still refer to them from the - // prevRunState object if we need to. - state.DiscardCheckResults() - refreshState.DiscardCheckResults() - - default: - state = inputState.DeepCopy().SyncWrapper() - // Only plan-like walks use refreshState and prevRunState - - // Discard the input state's check results, because we should create - // a new set as a result of the graph walk. - state.DiscardCheckResults() - } - - changes := opts.Changes - if changes == nil { - // Several of our non-plan walks end up sharing codepaths with the - // plan walk and thus expect to generate planned changes even though - // we don't care about them. To avoid those crashing, we'll just - // insert a placeholder changes object which'll get discarded - // afterwards. - changes = plans.NewChanges() - } - - if opts.Config == nil { - panic("Context.graphWalker call without Config") - } - - checkState := checks.NewState(opts.Config) - if opts.PlanTimeCheckResults != nil { - // We'll re-report all of the same objects we determined during the - // plan phase so that we can repeat the checks during the apply - // phase to finalize them. - for _, configElem := range opts.PlanTimeCheckResults.ConfigResults.Elems { - if configElem.Value.ObjectAddrsKnown() { - configAddr := configElem.Key - checkState.ReportCheckableObjects(configAddr, configElem.Value.ObjectResults.Keys()) - } - } - } - - return &ContextGraphWalker{ - Context: c, - State: state, - Config: opts.Config, - RefreshState: refreshState, - PrevRunState: prevRunState, - Changes: changes.SyncWrapper(), - Checks: checkState, - InstanceExpander: instances.NewExpander(), - MoveResults: opts.MoveResults, - Operation: operation, - StopContext: c.runContext, - } -} diff --git a/internal/terraform/diagnostics.go b/internal/terraform/diagnostics.go deleted file mode 100644 index 26f22f06ce6c..000000000000 --- a/internal/terraform/diagnostics.go +++ /dev/null @@ -1,42 +0,0 @@ -package terraform - -import ( - "github.com/hashicorp/terraform/internal/tfdiags" -) - -// This file contains some package-local helpers for working with diagnostics. -// For the main diagnostics API, see the separate "tfdiags" package. - -// diagnosticCausedByUnknown is an implementation of -// tfdiags.DiagnosticExtraBecauseUnknown which we can use in the "Extra" field -// of a diagnostic to indicate that the problem was caused by unknown values -// being involved in an expression evaluation. -// -// When using this, set the Extra to diagnosticCausedByUnknown(true) and also -// populate the EvalContext and Expression fields of the diagnostic so that -// the diagnostic renderer can use all of that information together to assist -// the user in understanding what was unknown. -type diagnosticCausedByUnknown bool - -var _ tfdiags.DiagnosticExtraBecauseUnknown = diagnosticCausedByUnknown(true) - -func (e diagnosticCausedByUnknown) DiagnosticCausedByUnknown() bool { - return bool(e) -} - -// diagnosticCausedBySensitive is an implementation of -// tfdiags.DiagnosticExtraBecauseSensitive which we can use in the "Extra" field -// of a diagnostic to indicate that the problem was caused by sensitive values -// being involved in an expression evaluation. -// -// When using this, set the Extra to diagnosticCausedBySensitive(true) and also -// populate the EvalContext and Expression fields of the diagnostic so that -// the diagnostic renderer can use all of that information together to assist -// the user in understanding what was sensitive. -type diagnosticCausedBySensitive bool - -var _ tfdiags.DiagnosticExtraBecauseSensitive = diagnosticCausedBySensitive(true) - -func (e diagnosticCausedBySensitive) DiagnosticCausedBySensitive() bool { - return bool(e) -} diff --git a/internal/terraform/eval_conditions.go b/internal/terraform/eval_conditions.go deleted file mode 100644 index 58877011ce5c..000000000000 --- a/internal/terraform/eval_conditions.go +++ /dev/null @@ -1,238 +0,0 @@ -package terraform - -import ( - "fmt" - "log" - "strings" - - "github.com/hashicorp/hcl/v2" - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/convert" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/checks" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/instances" - "github.com/hashicorp/terraform/internal/lang" - "github.com/hashicorp/terraform/internal/lang/marks" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -// evalCheckRules ensures that all of the given check rules pass against -// the given HCL evaluation context. -// -// If any check rules produce an unknown result then they will be silently -// ignored on the assumption that the same checks will be run again later -// with fewer unknown values in the EvalContext. -// -// If any of the rules do not pass, the returned diagnostics will contain -// errors. Otherwise, it will either be empty or contain only warnings. -func evalCheckRules(typ addrs.CheckType, rules []*configs.CheckRule, ctx EvalContext, self addrs.Checkable, keyData instances.RepetitionData, diagSeverity tfdiags.Severity) tfdiags.Diagnostics { - var diags tfdiags.Diagnostics - - checkState := ctx.Checks() - if !checkState.ConfigHasChecks(self.ConfigCheckable()) { - // We have nothing to do if this object doesn't have any checks, - // but the "rules" slice should agree that we don't. - if ct := len(rules); ct != 0 { - panic(fmt.Sprintf("check state says that %s should have no rules, but it has %d", self, ct)) - } - return diags - } - - if len(rules) == 0 { - // Nothing to do - return nil - } - - severity := diagSeverity.ToHCL() - - for i, rule := range rules { - result, ruleDiags := evalCheckRule(typ, rule, ctx, self, keyData, severity) - diags = diags.Append(ruleDiags) - - log.Printf("[TRACE] evalCheckRules: %s status is now %s", self, result.Status) - if result.Status == checks.StatusFail { - checkState.ReportCheckFailure(self, typ, i, result.FailureMessage) - } else { - checkState.ReportCheckResult(self, typ, i, result.Status) - } - } - - return diags -} - -type checkResult struct { - Status checks.Status - FailureMessage string -} - -func evalCheckRule(typ addrs.CheckType, rule *configs.CheckRule, ctx EvalContext, self addrs.Checkable, keyData instances.RepetitionData, severity hcl.DiagnosticSeverity) (checkResult, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - const errInvalidCondition = "Invalid condition result" - - refs, moreDiags := lang.ReferencesInExpr(rule.Condition) - diags = diags.Append(moreDiags) - moreRefs, moreDiags := lang.ReferencesInExpr(rule.ErrorMessage) - diags = diags.Append(moreDiags) - refs = append(refs, moreRefs...) - - var selfReference addrs.Referenceable - // Only resource postconditions can refer to self - if typ == addrs.ResourcePostcondition { - switch s := self.(type) { - case addrs.AbsResourceInstance: - selfReference = s.Resource - default: - panic(fmt.Sprintf("Invalid self reference type %t", self)) - } - } - scope := ctx.EvaluationScope(selfReference, keyData) - - hclCtx, moreDiags := scope.EvalContext(refs) - diags = diags.Append(moreDiags) - - resultVal, hclDiags := rule.Condition.Value(hclCtx) - diags = diags.Append(hclDiags) - - // NOTE: Intentionally not passing the caller's selected severity in here, - // because this reports errors in the configuration itself, not the failure - // of an otherwise-valid condition. - errorMessage, moreDiags := evalCheckErrorMessage(rule.ErrorMessage, hclCtx) - diags = diags.Append(moreDiags) - - if diags.HasErrors() { - log.Printf("[TRACE] evalCheckRule: %s: %s", typ, diags.Err().Error()) - return checkResult{Status: checks.StatusError}, diags - } - - if !resultVal.IsKnown() { - // We'll wait until we've learned more, then. - return checkResult{Status: checks.StatusUnknown}, diags - } - if resultVal.IsNull() { - // NOTE: Intentionally not passing the caller's selected severity in here, - // because this reports errors in the configuration itself, not the failure - // of an otherwise-valid condition. - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: errInvalidCondition, - Detail: "Condition expression must return either true or false, not null.", - Subject: rule.Condition.Range().Ptr(), - Expression: rule.Condition, - EvalContext: hclCtx, - }) - return checkResult{Status: checks.StatusError}, diags - } - var err error - resultVal, err = convert.Convert(resultVal, cty.Bool) - if err != nil { - // NOTE: Intentionally not passing the caller's selected severity in here, - // because this reports errors in the configuration itself, not the failure - // of an otherwise-valid condition. - detail := fmt.Sprintf("Invalid condition result value: %s.", tfdiags.FormatError(err)) - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: errInvalidCondition, - Detail: detail, - Subject: rule.Condition.Range().Ptr(), - Expression: rule.Condition, - EvalContext: hclCtx, - }) - return checkResult{Status: checks.StatusError}, diags - } - - // The condition result may be marked if the expression refers to a - // sensitive value. - resultVal, _ = resultVal.Unmark() - - status := checks.StatusForCtyValue(resultVal) - - if status != checks.StatusFail { - return checkResult{Status: status}, diags - } - - errorMessageForDiags := errorMessage - if errorMessageForDiags == "" { - errorMessageForDiags = "This check failed, but has an invalid error message as described in the other accompanying messages." - } - diags = diags.Append(&hcl.Diagnostic{ - // The caller gets to choose the severity of this one, because we - // treat condition failures as warnings in the presence of - // certain special planning options. - Severity: severity, - Summary: fmt.Sprintf("%s failed", typ.Description()), - Detail: errorMessageForDiags, - Subject: rule.Condition.Range().Ptr(), - Expression: rule.Condition, - EvalContext: hclCtx, - }) - - return checkResult{ - Status: status, - FailureMessage: errorMessage, - }, diags -} - -// evalCheckErrorMessage makes a best effort to evaluate the given expression, -// as an error message string. -// -// It will either return a non-empty message string or it'll return diagnostics -// with either errors or warnings that explain why the given expression isn't -// acceptable. -func evalCheckErrorMessage(expr hcl.Expression, hclCtx *hcl.EvalContext) (string, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - - val, hclDiags := expr.Value(hclCtx) - diags = diags.Append(hclDiags) - if hclDiags.HasErrors() { - return "", diags - } - - val, err := convert.Convert(val, cty.String) - if err != nil { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid error message", - Detail: fmt.Sprintf("Unsuitable value for error message: %s.", tfdiags.FormatError(err)), - Subject: expr.Range().Ptr(), - Expression: expr, - EvalContext: hclCtx, - }) - return "", diags - } - if !val.IsKnown() { - return "", diags - } - if val.IsNull() { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid error message", - Detail: "Unsuitable value for error message: must not be null.", - Subject: expr.Range().Ptr(), - Expression: expr, - EvalContext: hclCtx, - }) - return "", diags - } - - val, valMarks := val.Unmark() - if _, sensitive := valMarks[marks.Sensitive]; sensitive { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagWarning, - Summary: "Error message refers to sensitive values", - Detail: `The error expression used to explain this condition refers to sensitive values, so Terraform will not display the resulting message. - -You can correct this by removing references to sensitive values, or by carefully using the nonsensitive() function if the expression will not reveal the sensitive data.`, - Subject: expr.Range().Ptr(), - Expression: expr, - EvalContext: hclCtx, - }) - return "", diags - } - - // NOTE: We've discarded any other marks the string might have been carrying, - // aside from the sensitive mark. - - return strings.TrimSpace(val.AsString()), diags -} diff --git a/internal/terraform/eval_context.go b/internal/terraform/eval_context.go deleted file mode 100644 index fedf223051ab..000000000000 --- a/internal/terraform/eval_context.go +++ /dev/null @@ -1,204 +0,0 @@ -package terraform - -import ( - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/checks" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/instances" - "github.com/hashicorp/terraform/internal/lang" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/provisioners" - "github.com/hashicorp/terraform/internal/refactoring" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" - "github.com/zclconf/go-cty/cty" -) - -// EvalContext is the interface that is given to eval nodes to execute. -type EvalContext interface { - // Stopped returns a channel that is closed when evaluation is stopped - // via Terraform.Context.Stop() - Stopped() <-chan struct{} - - // Path is the current module path. - Path() addrs.ModuleInstance - - // Hook is used to call hook methods. The callback is called for each - // hook and should return the hook action to take and the error. - Hook(func(Hook) (HookAction, error)) error - - // Input is the UIInput object for interacting with the UI. - Input() UIInput - - // InitProvider initializes the provider with the given address, and returns - // the implementation of the resource provider or an error. - // - // It is an error to initialize the same provider more than once. This - // method will panic if the module instance address of the given provider - // configuration does not match the Path() of the EvalContext. - InitProvider(addr addrs.AbsProviderConfig) (providers.Interface, error) - - // Provider gets the provider instance with the given address (already - // initialized) or returns nil if the provider isn't initialized. - // - // This method expects an _absolute_ provider configuration address, since - // resources in one module are able to use providers from other modules. - // InitProvider must've been called on the EvalContext of the module - // that owns the given provider before calling this method. - Provider(addrs.AbsProviderConfig) providers.Interface - - // ProviderSchema retrieves the schema for a particular provider, which - // must have already been initialized with InitProvider. - // - // This method expects an _absolute_ provider configuration address, since - // resources in one module are able to use providers from other modules. - ProviderSchema(addrs.AbsProviderConfig) (*ProviderSchema, error) - - // CloseProvider closes provider connections that aren't needed anymore. - // - // This method will panic if the module instance address of the given - // provider configuration does not match the Path() of the EvalContext. - CloseProvider(addrs.AbsProviderConfig) error - - // ConfigureProvider configures the provider with the given - // configuration. This is a separate context call because this call - // is used to store the provider configuration for inheritance lookups - // with ParentProviderConfig(). - // - // This method will panic if the module instance address of the given - // provider configuration does not match the Path() of the EvalContext. - ConfigureProvider(addrs.AbsProviderConfig, cty.Value) tfdiags.Diagnostics - - // ProviderInput and SetProviderInput are used to configure providers - // from user input. - // - // These methods will panic if the module instance address of the given - // provider configuration does not match the Path() of the EvalContext. - ProviderInput(addrs.AbsProviderConfig) map[string]cty.Value - SetProviderInput(addrs.AbsProviderConfig, map[string]cty.Value) - - // Provisioner gets the provisioner instance with the given name. - Provisioner(string) (provisioners.Interface, error) - - // ProvisionerSchema retrieves the main configuration schema for a - // particular provisioner, which must have already been initialized with - // InitProvisioner. - ProvisionerSchema(string) (*configschema.Block, error) - - // CloseProvisioner closes all provisioner plugins. - CloseProvisioners() error - - // EvaluateBlock takes the given raw configuration block and associated - // schema and evaluates it to produce a value of an object type that - // conforms to the implied type of the schema. - // - // The "self" argument is optional. If given, it is the referenceable - // address that the name "self" should behave as an alias for when - // evaluating. Set this to nil if the "self" object should not be available. - // - // The "key" argument is also optional. If given, it is the instance key - // of the current object within the multi-instance container it belongs - // to. For example, on a resource block with "count" set this should be - // set to a different addrs.IntKey for each instance created from that - // block. Set this to addrs.NoKey if not appropriate. - // - // The returned body is an expanded version of the given body, with any - // "dynamic" blocks replaced with zero or more static blocks. This can be - // used to extract correct source location information about attributes of - // the returned object value. - EvaluateBlock(body hcl.Body, schema *configschema.Block, self addrs.Referenceable, keyData InstanceKeyEvalData) (cty.Value, hcl.Body, tfdiags.Diagnostics) - - // EvaluateExpr takes the given HCL expression and evaluates it to produce - // a value. - // - // The "self" argument is optional. If given, it is the referenceable - // address that the name "self" should behave as an alias for when - // evaluating. Set this to nil if the "self" object should not be available. - EvaluateExpr(expr hcl.Expression, wantType cty.Type, self addrs.Referenceable) (cty.Value, tfdiags.Diagnostics) - - // EvaluateReplaceTriggeredBy takes the raw reference expression from the - // config, and returns the evaluated *addrs.Reference along with a boolean - // indicating if that reference forces replacement. - EvaluateReplaceTriggeredBy(expr hcl.Expression, repData instances.RepetitionData) (*addrs.Reference, bool, tfdiags.Diagnostics) - - // EvaluationScope returns a scope that can be used to evaluate reference - // addresses in this context. - EvaluationScope(self addrs.Referenceable, keyData InstanceKeyEvalData) *lang.Scope - - // SetRootModuleArgument defines the value for one variable of the root - // module. The caller must ensure that given value is a suitable - // "final value" for the variable, which means that it's already converted - // and validated to match any configured constraints and validation rules. - // - // Calling this function multiple times with the same variable address - // will silently overwrite the value provided by a previous call. - SetRootModuleArgument(addrs.InputVariable, cty.Value) - - // SetModuleCallArgument defines the value for one input variable of a - // particular child module call. The caller must ensure that the given - // value is a suitable "final value" for the variable, which means that - // it's already converted and validated to match any configured - // constraints and validation rules. - // - // Calling this function multiple times with the same variable address - // will silently overwrite the value provided by a previous call. - SetModuleCallArgument(addrs.ModuleCallInstance, addrs.InputVariable, cty.Value) - - // GetVariableValue returns the value provided for the input variable with - // the given address, or cty.DynamicVal if the variable hasn't been assigned - // a value yet. - // - // Most callers should deal with variable values only indirectly via - // EvaluationScope and the other expression evaluation functions, but - // this is provided because variables tend to be evaluated outside of - // the context of the module they belong to and so we sometimes need to - // override the normal expression evaluation behavior. - GetVariableValue(addr addrs.AbsInputVariableInstance) cty.Value - - // Changes returns the writer object that can be used to write new proposed - // changes into the global changes set. - Changes() *plans.ChangesSync - - // State returns a wrapper object that provides safe concurrent access to - // the global state. - State() *states.SyncState - - // Checks returns the object that tracks the state of any custom checks - // declared in the configuration. - Checks() *checks.State - - // RefreshState returns a wrapper object that provides safe concurrent - // access to the state used to store the most recently refreshed resource - // values. - RefreshState() *states.SyncState - - // PrevRunState returns a wrapper object that provides safe concurrent - // access to the state which represents the result of the previous run, - // updated only so that object data conforms to current schemas for - // meaningful comparison with RefreshState. - PrevRunState() *states.SyncState - - // InstanceExpander returns a helper object for tracking the expansion of - // graph nodes during the plan phase in response to "count" and "for_each" - // arguments. - // - // The InstanceExpander is a global object that is shared across all of the - // EvalContext objects for a given configuration. - InstanceExpander() *instances.Expander - - // MoveResults returns a map describing the results of handling any - // resource instance move statements prior to the graph walk, so that - // the graph walk can then record that information appropriately in other - // artifacts produced by the graph walk. - // - // This data structure is created prior to the graph walk and read-only - // thereafter, so callers must not modify the returned map or any other - // objects accessible through it. - MoveResults() refactoring.MoveResults - - // WithPath returns a copy of the context with the internal path set to the - // path argument. - WithPath(path addrs.ModuleInstance) EvalContext -} diff --git a/internal/terraform/eval_context_builtin.go b/internal/terraform/eval_context_builtin.go deleted file mode 100644 index d66b9dd08060..000000000000 --- a/internal/terraform/eval_context_builtin.go +++ /dev/null @@ -1,504 +0,0 @@ -package terraform - -import ( - "context" - "fmt" - "log" - "sync" - - "github.com/hashicorp/terraform/internal/checks" - "github.com/hashicorp/terraform/internal/instances" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/provisioners" - "github.com/hashicorp/terraform/internal/refactoring" - "github.com/hashicorp/terraform/version" - - "github.com/hashicorp/terraform/internal/states" - - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/lang" - "github.com/hashicorp/terraform/internal/tfdiags" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/zclconf/go-cty/cty" -) - -// BuiltinEvalContext is an EvalContext implementation that is used by -// Terraform by default. -type BuiltinEvalContext struct { - // StopContext is the context used to track whether we're complete - StopContext context.Context - - // PathValue is the Path that this context is operating within. - PathValue addrs.ModuleInstance - - // pathSet indicates that this context was explicitly created for a - // specific path, and can be safely used for evaluation. This lets us - // differentiate between PathValue being unset, and the zero value which is - // equivalent to RootModuleInstance. Path and Evaluation methods will - // panic if this is not set. - pathSet bool - - // Evaluator is used for evaluating expressions within the scope of this - // eval context. - Evaluator *Evaluator - - // VariableValues contains the variable values across all modules. This - // structure is shared across the entire containing context, and so it - // may be accessed only when holding VariableValuesLock. - // The keys of the first level of VariableValues are the string - // representations of addrs.ModuleInstance values. The second-level keys - // are variable names within each module instance. - VariableValues map[string]map[string]cty.Value - VariableValuesLock *sync.Mutex - - // Plugins is a library of plugin components (providers and provisioners) - // available for use during a graph walk. - Plugins *contextPlugins - - Hooks []Hook - InputValue UIInput - ProviderCache map[string]providers.Interface - ProviderInputConfig map[string]map[string]cty.Value - ProviderLock *sync.Mutex - ProvisionerCache map[string]provisioners.Interface - ProvisionerLock *sync.Mutex - ChangesValue *plans.ChangesSync - StateValue *states.SyncState - ChecksValue *checks.State - RefreshStateValue *states.SyncState - PrevRunStateValue *states.SyncState - InstanceExpanderValue *instances.Expander - MoveResultsValue refactoring.MoveResults -} - -// BuiltinEvalContext implements EvalContext -var _ EvalContext = (*BuiltinEvalContext)(nil) - -func (ctx *BuiltinEvalContext) WithPath(path addrs.ModuleInstance) EvalContext { - newCtx := *ctx - newCtx.pathSet = true - newCtx.PathValue = path - return &newCtx -} - -func (ctx *BuiltinEvalContext) Stopped() <-chan struct{} { - // This can happen during tests. During tests, we just block forever. - if ctx.StopContext == nil { - return nil - } - - return ctx.StopContext.Done() -} - -func (ctx *BuiltinEvalContext) Hook(fn func(Hook) (HookAction, error)) error { - for _, h := range ctx.Hooks { - action, err := fn(h) - if err != nil { - return err - } - - switch action { - case HookActionContinue: - continue - case HookActionHalt: - // Return an early exit error to trigger an early exit - log.Printf("[WARN] Early exit triggered by hook: %T", h) - return nil - } - } - - return nil -} - -func (ctx *BuiltinEvalContext) Input() UIInput { - return ctx.InputValue -} - -func (ctx *BuiltinEvalContext) InitProvider(addr addrs.AbsProviderConfig) (providers.Interface, error) { - // If we already initialized, it is an error - if p := ctx.Provider(addr); p != nil { - return nil, fmt.Errorf("%s is already initialized", addr) - } - - // Warning: make sure to acquire these locks AFTER the call to Provider - // above, since it also acquires locks. - ctx.ProviderLock.Lock() - defer ctx.ProviderLock.Unlock() - - key := addr.String() - - p, err := ctx.Plugins.NewProviderInstance(addr.Provider) - if err != nil { - return nil, err - } - - log.Printf("[TRACE] BuiltinEvalContext: Initialized %q provider for %s", addr.String(), addr) - ctx.ProviderCache[key] = p - - return p, nil -} - -func (ctx *BuiltinEvalContext) Provider(addr addrs.AbsProviderConfig) providers.Interface { - ctx.ProviderLock.Lock() - defer ctx.ProviderLock.Unlock() - - return ctx.ProviderCache[addr.String()] -} - -func (ctx *BuiltinEvalContext) ProviderSchema(addr addrs.AbsProviderConfig) (*ProviderSchema, error) { - return ctx.Plugins.ProviderSchema(addr.Provider) -} - -func (ctx *BuiltinEvalContext) CloseProvider(addr addrs.AbsProviderConfig) error { - ctx.ProviderLock.Lock() - defer ctx.ProviderLock.Unlock() - - key := addr.String() - provider := ctx.ProviderCache[key] - if provider != nil { - delete(ctx.ProviderCache, key) - return provider.Close() - } - - return nil -} - -func (ctx *BuiltinEvalContext) ConfigureProvider(addr addrs.AbsProviderConfig, cfg cty.Value) tfdiags.Diagnostics { - var diags tfdiags.Diagnostics - if !addr.Module.Equal(ctx.Path().Module()) { - // This indicates incorrect use of ConfigureProvider: it should be used - // only from the module that the provider configuration belongs to. - panic(fmt.Sprintf("%s configured by wrong module %s", addr, ctx.Path())) - } - - p := ctx.Provider(addr) - if p == nil { - diags = diags.Append(fmt.Errorf("%s not initialized", addr)) - return diags - } - - providerSchema, err := ctx.ProviderSchema(addr) - if err != nil { - diags = diags.Append(fmt.Errorf("failed to read schema for %s: %s", addr, err)) - return diags - } - if providerSchema == nil { - diags = diags.Append(fmt.Errorf("schema for %s is not available", addr)) - return diags - } - - req := providers.ConfigureProviderRequest{ - TerraformVersion: version.String(), - Config: cfg, - } - - resp := p.ConfigureProvider(req) - return resp.Diagnostics -} - -func (ctx *BuiltinEvalContext) ProviderInput(pc addrs.AbsProviderConfig) map[string]cty.Value { - ctx.ProviderLock.Lock() - defer ctx.ProviderLock.Unlock() - - if !pc.Module.Equal(ctx.Path().Module()) { - // This indicates incorrect use of InitProvider: it should be used - // only from the module that the provider configuration belongs to. - panic(fmt.Sprintf("%s initialized by wrong module %s", pc, ctx.Path())) - } - - if !ctx.Path().IsRoot() { - // Only root module provider configurations can have input. - return nil - } - - return ctx.ProviderInputConfig[pc.String()] -} - -func (ctx *BuiltinEvalContext) SetProviderInput(pc addrs.AbsProviderConfig, c map[string]cty.Value) { - absProvider := pc - if !pc.Module.IsRoot() { - // Only root module provider configurations can have input. - log.Printf("[WARN] BuiltinEvalContext: attempt to SetProviderInput for non-root module") - return - } - - // Save the configuration - ctx.ProviderLock.Lock() - ctx.ProviderInputConfig[absProvider.String()] = c - ctx.ProviderLock.Unlock() -} - -func (ctx *BuiltinEvalContext) Provisioner(n string) (provisioners.Interface, error) { - ctx.ProvisionerLock.Lock() - defer ctx.ProvisionerLock.Unlock() - - p, ok := ctx.ProvisionerCache[n] - if !ok { - var err error - p, err = ctx.Plugins.NewProvisionerInstance(n) - if err != nil { - return nil, err - } - - ctx.ProvisionerCache[n] = p - } - - return p, nil -} - -func (ctx *BuiltinEvalContext) ProvisionerSchema(n string) (*configschema.Block, error) { - return ctx.Plugins.ProvisionerSchema(n) -} - -func (ctx *BuiltinEvalContext) CloseProvisioners() error { - var diags tfdiags.Diagnostics - ctx.ProvisionerLock.Lock() - defer ctx.ProvisionerLock.Unlock() - - for name, prov := range ctx.ProvisionerCache { - err := prov.Close() - if err != nil { - diags = diags.Append(fmt.Errorf("provisioner.Close %s: %s", name, err)) - } - } - - return diags.Err() -} - -func (ctx *BuiltinEvalContext) EvaluateBlock(body hcl.Body, schema *configschema.Block, self addrs.Referenceable, keyData InstanceKeyEvalData) (cty.Value, hcl.Body, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - scope := ctx.EvaluationScope(self, keyData) - body, evalDiags := scope.ExpandBlock(body, schema) - diags = diags.Append(evalDiags) - val, evalDiags := scope.EvalBlock(body, schema) - diags = diags.Append(evalDiags) - return val, body, diags -} - -func (ctx *BuiltinEvalContext) EvaluateExpr(expr hcl.Expression, wantType cty.Type, self addrs.Referenceable) (cty.Value, tfdiags.Diagnostics) { - scope := ctx.EvaluationScope(self, EvalDataForNoInstanceKey) - return scope.EvalExpr(expr, wantType) -} - -func (ctx *BuiltinEvalContext) EvaluateReplaceTriggeredBy(expr hcl.Expression, repData instances.RepetitionData) (*addrs.Reference, bool, tfdiags.Diagnostics) { - - // get the reference to lookup changes in the plan - ref, diags := evalReplaceTriggeredByExpr(expr, repData) - if diags.HasErrors() { - return nil, false, diags - } - - var changes []*plans.ResourceInstanceChangeSrc - // store the address once we get it for validation - var resourceAddr addrs.Resource - - // The reference is either a resource or resource instance - switch sub := ref.Subject.(type) { - case addrs.Resource: - resourceAddr = sub - rc := sub.Absolute(ctx.Path()) - changes = ctx.Changes().GetChangesForAbsResource(rc) - case addrs.ResourceInstance: - resourceAddr = sub.ContainingResource() - rc := sub.Absolute(ctx.Path()) - change := ctx.Changes().GetResourceInstanceChange(rc, states.CurrentGen) - if change != nil { - // we'll generate an error below if there was no change - changes = append(changes, change) - } - } - - // Do some validation to make sure we are expecting a change at all - cfg := ctx.Evaluator.Config.Descendent(ctx.Path().Module()) - resCfg := cfg.Module.ResourceByAddr(resourceAddr) - if resCfg == nil { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: `Reference to undeclared resource`, - Detail: fmt.Sprintf(`A resource %s has not been declared in %s`, ref.Subject, moduleDisplayAddr(ctx.Path())), - Subject: expr.Range().Ptr(), - }) - return nil, false, diags - } - - if len(changes) == 0 { - // If the resource is valid there should always be at least one change. - diags = diags.Append(fmt.Errorf("no change found for %s in %s", ref.Subject, moduleDisplayAddr(ctx.Path()))) - return nil, false, diags - } - - // If we don't have a traversal beyond the resource, then we can just look - // for any change. - if len(ref.Remaining) == 0 { - for _, c := range changes { - switch c.ChangeSrc.Action { - // Only immediate changes to the resource will trigger replacement. - case plans.Update, plans.DeleteThenCreate, plans.CreateThenDelete: - return ref, true, diags - } - } - - // no change triggered - return nil, false, diags - } - - // This must be an instances to have a remaining traversal, which means a - // single change. - change := changes[0] - - // Make sure the change is actionable. A create or delete action will have - // a change in value, but are not valid for our purposes here. - switch change.ChangeSrc.Action { - case plans.Update, plans.DeleteThenCreate, plans.CreateThenDelete: - // OK - default: - return nil, false, diags - } - - // Since we have a traversal after the resource reference, we will need to - // decode the changes, which means we need a schema. - providerAddr := change.ProviderAddr - schema, err := ctx.ProviderSchema(providerAddr) - if err != nil { - diags = diags.Append(err) - return nil, false, diags - } - - resAddr := change.Addr.ContainingResource().Resource - resSchema, _ := schema.SchemaForResourceType(resAddr.Mode, resAddr.Type) - ty := resSchema.ImpliedType() - - before, err := change.ChangeSrc.Before.Decode(ty) - if err != nil { - diags = diags.Append(err) - return nil, false, diags - } - - after, err := change.ChangeSrc.After.Decode(ty) - if err != nil { - diags = diags.Append(err) - return nil, false, diags - } - - path := traversalToPath(ref.Remaining) - attrBefore, _ := path.Apply(before) - attrAfter, _ := path.Apply(after) - - if attrBefore == cty.NilVal || attrAfter == cty.NilVal { - replace := attrBefore != attrAfter - return ref, replace, diags - } - - replace := !attrBefore.RawEquals(attrAfter) - - return ref, replace, diags -} - -func (ctx *BuiltinEvalContext) EvaluationScope(self addrs.Referenceable, keyData instances.RepetitionData) *lang.Scope { - if !ctx.pathSet { - panic("context path not set") - } - data := &evaluationStateData{ - Evaluator: ctx.Evaluator, - ModulePath: ctx.PathValue, - InstanceKeyData: keyData, - Operation: ctx.Evaluator.Operation, - } - scope := ctx.Evaluator.Scope(data, self) - - // ctx.PathValue is the path of the module that contains whatever - // expression the caller will be trying to evaluate, so this will - // activate only the experiments from that particular module, to - // be consistent with how experiment checking in the "configs" - // package itself works. The nil check here is for robustness in - // incompletely-mocked testing situations; mc should never be nil in - // real situations. - if mc := ctx.Evaluator.Config.DescendentForInstance(ctx.PathValue); mc != nil { - scope.SetActiveExperiments(mc.Module.ActiveExperiments) - } - return scope -} - -func (ctx *BuiltinEvalContext) Path() addrs.ModuleInstance { - if !ctx.pathSet { - panic("context path not set") - } - return ctx.PathValue -} - -func (ctx *BuiltinEvalContext) SetRootModuleArgument(addr addrs.InputVariable, v cty.Value) { - ctx.VariableValuesLock.Lock() - defer ctx.VariableValuesLock.Unlock() - - log.Printf("[TRACE] BuiltinEvalContext: Storing final value for variable %s", addr.Absolute(addrs.RootModuleInstance)) - key := addrs.RootModuleInstance.String() - args := ctx.VariableValues[key] - if args == nil { - args = make(map[string]cty.Value) - ctx.VariableValues[key] = args - } - args[addr.Name] = v -} - -func (ctx *BuiltinEvalContext) SetModuleCallArgument(callAddr addrs.ModuleCallInstance, varAddr addrs.InputVariable, v cty.Value) { - ctx.VariableValuesLock.Lock() - defer ctx.VariableValuesLock.Unlock() - - if !ctx.pathSet { - panic("context path not set") - } - - childPath := callAddr.ModuleInstance(ctx.PathValue) - log.Printf("[TRACE] BuiltinEvalContext: Storing final value for variable %s", varAddr.Absolute(childPath)) - key := childPath.String() - args := ctx.VariableValues[key] - if args == nil { - args = make(map[string]cty.Value) - ctx.VariableValues[key] = args - } - args[varAddr.Name] = v -} - -func (ctx *BuiltinEvalContext) GetVariableValue(addr addrs.AbsInputVariableInstance) cty.Value { - ctx.VariableValuesLock.Lock() - defer ctx.VariableValuesLock.Unlock() - - modKey := addr.Module.String() - modVars := ctx.VariableValues[modKey] - val, ok := modVars[addr.Variable.Name] - if !ok { - return cty.DynamicVal - } - return val -} - -func (ctx *BuiltinEvalContext) Changes() *plans.ChangesSync { - return ctx.ChangesValue -} - -func (ctx *BuiltinEvalContext) State() *states.SyncState { - return ctx.StateValue -} - -func (ctx *BuiltinEvalContext) Checks() *checks.State { - return ctx.ChecksValue -} - -func (ctx *BuiltinEvalContext) RefreshState() *states.SyncState { - return ctx.RefreshStateValue -} - -func (ctx *BuiltinEvalContext) PrevRunState() *states.SyncState { - return ctx.PrevRunStateValue -} - -func (ctx *BuiltinEvalContext) InstanceExpander() *instances.Expander { - return ctx.InstanceExpanderValue -} - -func (ctx *BuiltinEvalContext) MoveResults() refactoring.MoveResults { - return ctx.MoveResultsValue -} diff --git a/internal/terraform/eval_context_builtin_test.go b/internal/terraform/eval_context_builtin_test.go deleted file mode 100644 index 0db0096a75ed..000000000000 --- a/internal/terraform/eval_context_builtin_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package terraform - -import ( - "reflect" - "sync" - "testing" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/providers" - "github.com/zclconf/go-cty/cty" -) - -func TestBuiltinEvalContextProviderInput(t *testing.T) { - var lock sync.Mutex - cache := make(map[string]map[string]cty.Value) - - ctx1 := testBuiltinEvalContext(t) - ctx1 = ctx1.WithPath(addrs.RootModuleInstance).(*BuiltinEvalContext) - ctx1.ProviderInputConfig = cache - ctx1.ProviderLock = &lock - - ctx2 := testBuiltinEvalContext(t) - ctx2 = ctx2.WithPath(addrs.RootModuleInstance.Child("child", addrs.NoKey)).(*BuiltinEvalContext) - ctx2.ProviderInputConfig = cache - ctx2.ProviderLock = &lock - - providerAddr1 := addrs.AbsProviderConfig{ - Module: addrs.RootModule, - Provider: addrs.NewDefaultProvider("foo"), - } - providerAddr2 := addrs.AbsProviderConfig{ - Module: addrs.RootModule.Child("child"), - Provider: addrs.NewDefaultProvider("foo"), - } - - expected1 := map[string]cty.Value{"value": cty.StringVal("foo")} - ctx1.SetProviderInput(providerAddr1, expected1) - - try2 := map[string]cty.Value{"value": cty.StringVal("bar")} - ctx2.SetProviderInput(providerAddr2, try2) // ignored because not a root module - - actual1 := ctx1.ProviderInput(providerAddr1) - actual2 := ctx2.ProviderInput(providerAddr2) - - if !reflect.DeepEqual(actual1, expected1) { - t.Errorf("wrong result 1\ngot: %#v\nwant: %#v", actual1, expected1) - } - if actual2 != nil { - t.Errorf("wrong result 2\ngot: %#v\nwant: %#v", actual2, nil) - } -} - -func TestBuildingEvalContextInitProvider(t *testing.T) { - var lock sync.Mutex - - testP := &MockProvider{} - - ctx := testBuiltinEvalContext(t) - ctx = ctx.WithPath(addrs.RootModuleInstance).(*BuiltinEvalContext) - ctx.ProviderLock = &lock - ctx.ProviderCache = make(map[string]providers.Interface) - ctx.Plugins = newContextPlugins(map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): providers.FactoryFixed(testP), - }, nil) - - providerAddrDefault := addrs.AbsProviderConfig{ - Module: addrs.RootModule, - Provider: addrs.NewDefaultProvider("test"), - } - providerAddrAlias := addrs.AbsProviderConfig{ - Module: addrs.RootModule, - Provider: addrs.NewDefaultProvider("test"), - Alias: "foo", - } - - _, err := ctx.InitProvider(providerAddrDefault) - if err != nil { - t.Fatalf("error initializing provider test: %s", err) - } - _, err = ctx.InitProvider(providerAddrAlias) - if err != nil { - t.Fatalf("error initializing provider test.foo: %s", err) - } -} - -func testBuiltinEvalContext(t *testing.T) *BuiltinEvalContext { - return &BuiltinEvalContext{} -} diff --git a/internal/terraform/eval_context_mock.go b/internal/terraform/eval_context_mock.go deleted file mode 100644 index 24159ef95502..000000000000 --- a/internal/terraform/eval_context_mock.go +++ /dev/null @@ -1,401 +0,0 @@ -package terraform - -import ( - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/checks" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/instances" - "github.com/hashicorp/terraform/internal/lang" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/provisioners" - "github.com/hashicorp/terraform/internal/refactoring" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/convert" -) - -// MockEvalContext is a mock version of EvalContext that can be used -// for tests. -type MockEvalContext struct { - StoppedCalled bool - StoppedValue <-chan struct{} - - HookCalled bool - HookHook Hook - HookError error - - InputCalled bool - InputInput UIInput - - InitProviderCalled bool - InitProviderType string - InitProviderAddr addrs.AbsProviderConfig - InitProviderProvider providers.Interface - InitProviderError error - - ProviderCalled bool - ProviderAddr addrs.AbsProviderConfig - ProviderProvider providers.Interface - - ProviderSchemaCalled bool - ProviderSchemaAddr addrs.AbsProviderConfig - ProviderSchemaSchema *ProviderSchema - ProviderSchemaError error - - CloseProviderCalled bool - CloseProviderAddr addrs.AbsProviderConfig - CloseProviderProvider providers.Interface - - ProviderInputCalled bool - ProviderInputAddr addrs.AbsProviderConfig - ProviderInputValues map[string]cty.Value - - SetProviderInputCalled bool - SetProviderInputAddr addrs.AbsProviderConfig - SetProviderInputValues map[string]cty.Value - - ConfigureProviderFn func( - addr addrs.AbsProviderConfig, - cfg cty.Value) tfdiags.Diagnostics // overrides the other values below, if set - ConfigureProviderCalled bool - ConfigureProviderAddr addrs.AbsProviderConfig - ConfigureProviderConfig cty.Value - ConfigureProviderDiags tfdiags.Diagnostics - - ProvisionerCalled bool - ProvisionerName string - ProvisionerProvisioner provisioners.Interface - - ProvisionerSchemaCalled bool - ProvisionerSchemaName string - ProvisionerSchemaSchema *configschema.Block - ProvisionerSchemaError error - - CloseProvisionersCalled bool - - EvaluateBlockCalled bool - EvaluateBlockBody hcl.Body - EvaluateBlockSchema *configschema.Block - EvaluateBlockSelf addrs.Referenceable - EvaluateBlockKeyData InstanceKeyEvalData - EvaluateBlockResultFunc func( - body hcl.Body, - schema *configschema.Block, - self addrs.Referenceable, - keyData InstanceKeyEvalData, - ) (cty.Value, hcl.Body, tfdiags.Diagnostics) // overrides the other values below, if set - EvaluateBlockResult cty.Value - EvaluateBlockExpandedBody hcl.Body - EvaluateBlockDiags tfdiags.Diagnostics - - EvaluateExprCalled bool - EvaluateExprExpr hcl.Expression - EvaluateExprWantType cty.Type - EvaluateExprSelf addrs.Referenceable - EvaluateExprResultFunc func( - expr hcl.Expression, - wantType cty.Type, - self addrs.Referenceable, - ) (cty.Value, tfdiags.Diagnostics) // overrides the other values below, if set - EvaluateExprResult cty.Value - EvaluateExprDiags tfdiags.Diagnostics - - EvaluationScopeCalled bool - EvaluationScopeSelf addrs.Referenceable - EvaluationScopeKeyData InstanceKeyEvalData - EvaluationScopeScope *lang.Scope - - PathCalled bool - PathPath addrs.ModuleInstance - - SetRootModuleArgumentCalled bool - SetRootModuleArgumentAddr addrs.InputVariable - SetRootModuleArgumentValue cty.Value - SetRootModuleArgumentFunc func(addr addrs.InputVariable, v cty.Value) - - SetModuleCallArgumentCalled bool - SetModuleCallArgumentModuleCall addrs.ModuleCallInstance - SetModuleCallArgumentVariable addrs.InputVariable - SetModuleCallArgumentValue cty.Value - SetModuleCallArgumentFunc func(callAddr addrs.ModuleCallInstance, varAddr addrs.InputVariable, v cty.Value) - - GetVariableValueCalled bool - GetVariableValueAddr addrs.AbsInputVariableInstance - GetVariableValueValue cty.Value - GetVariableValueFunc func(addr addrs.AbsInputVariableInstance) cty.Value // supersedes GetVariableValueValue - - ChangesCalled bool - ChangesChanges *plans.ChangesSync - - StateCalled bool - StateState *states.SyncState - - ChecksCalled bool - ChecksState *checks.State - - RefreshStateCalled bool - RefreshStateState *states.SyncState - - PrevRunStateCalled bool - PrevRunStateState *states.SyncState - - MoveResultsCalled bool - MoveResultsResults refactoring.MoveResults - - InstanceExpanderCalled bool - InstanceExpanderExpander *instances.Expander -} - -// MockEvalContext implements EvalContext -var _ EvalContext = (*MockEvalContext)(nil) - -func (c *MockEvalContext) Stopped() <-chan struct{} { - c.StoppedCalled = true - return c.StoppedValue -} - -func (c *MockEvalContext) Hook(fn func(Hook) (HookAction, error)) error { - c.HookCalled = true - if c.HookHook != nil { - if _, err := fn(c.HookHook); err != nil { - return err - } - } - - return c.HookError -} - -func (c *MockEvalContext) Input() UIInput { - c.InputCalled = true - return c.InputInput -} - -func (c *MockEvalContext) InitProvider(addr addrs.AbsProviderConfig) (providers.Interface, error) { - c.InitProviderCalled = true - c.InitProviderType = addr.String() - c.InitProviderAddr = addr - return c.InitProviderProvider, c.InitProviderError -} - -func (c *MockEvalContext) Provider(addr addrs.AbsProviderConfig) providers.Interface { - c.ProviderCalled = true - c.ProviderAddr = addr - return c.ProviderProvider -} - -func (c *MockEvalContext) ProviderSchema(addr addrs.AbsProviderConfig) (*ProviderSchema, error) { - c.ProviderSchemaCalled = true - c.ProviderSchemaAddr = addr - return c.ProviderSchemaSchema, c.ProviderSchemaError -} - -func (c *MockEvalContext) CloseProvider(addr addrs.AbsProviderConfig) error { - c.CloseProviderCalled = true - c.CloseProviderAddr = addr - return nil -} - -func (c *MockEvalContext) ConfigureProvider(addr addrs.AbsProviderConfig, cfg cty.Value) tfdiags.Diagnostics { - - c.ConfigureProviderCalled = true - c.ConfigureProviderAddr = addr - c.ConfigureProviderConfig = cfg - if c.ConfigureProviderFn != nil { - return c.ConfigureProviderFn(addr, cfg) - } - return c.ConfigureProviderDiags -} - -func (c *MockEvalContext) ProviderInput(addr addrs.AbsProviderConfig) map[string]cty.Value { - c.ProviderInputCalled = true - c.ProviderInputAddr = addr - return c.ProviderInputValues -} - -func (c *MockEvalContext) SetProviderInput(addr addrs.AbsProviderConfig, vals map[string]cty.Value) { - c.SetProviderInputCalled = true - c.SetProviderInputAddr = addr - c.SetProviderInputValues = vals -} - -func (c *MockEvalContext) Provisioner(n string) (provisioners.Interface, error) { - c.ProvisionerCalled = true - c.ProvisionerName = n - return c.ProvisionerProvisioner, nil -} - -func (c *MockEvalContext) ProvisionerSchema(n string) (*configschema.Block, error) { - c.ProvisionerSchemaCalled = true - c.ProvisionerSchemaName = n - return c.ProvisionerSchemaSchema, c.ProvisionerSchemaError -} - -func (c *MockEvalContext) CloseProvisioners() error { - c.CloseProvisionersCalled = true - return nil -} - -func (c *MockEvalContext) EvaluateBlock(body hcl.Body, schema *configschema.Block, self addrs.Referenceable, keyData InstanceKeyEvalData) (cty.Value, hcl.Body, tfdiags.Diagnostics) { - c.EvaluateBlockCalled = true - c.EvaluateBlockBody = body - c.EvaluateBlockSchema = schema - c.EvaluateBlockSelf = self - c.EvaluateBlockKeyData = keyData - if c.EvaluateBlockResultFunc != nil { - return c.EvaluateBlockResultFunc(body, schema, self, keyData) - } - return c.EvaluateBlockResult, c.EvaluateBlockExpandedBody, c.EvaluateBlockDiags -} - -func (c *MockEvalContext) EvaluateExpr(expr hcl.Expression, wantType cty.Type, self addrs.Referenceable) (cty.Value, tfdiags.Diagnostics) { - c.EvaluateExprCalled = true - c.EvaluateExprExpr = expr - c.EvaluateExprWantType = wantType - c.EvaluateExprSelf = self - if c.EvaluateExprResultFunc != nil { - return c.EvaluateExprResultFunc(expr, wantType, self) - } - return c.EvaluateExprResult, c.EvaluateExprDiags -} - -func (c *MockEvalContext) EvaluateReplaceTriggeredBy(hcl.Expression, instances.RepetitionData) (*addrs.Reference, bool, tfdiags.Diagnostics) { - return nil, false, nil -} - -// installSimpleEval is a helper to install a simple mock implementation of -// both EvaluateBlock and EvaluateExpr into the receiver. -// -// These default implementations will either evaluate the given input against -// the scope in field EvaluationScopeScope or, if it is nil, with no eval -// context at all so that only constant values may be used. -// -// This function overwrites any existing functions installed in fields -// EvaluateBlockResultFunc and EvaluateExprResultFunc. -func (c *MockEvalContext) installSimpleEval() { - c.EvaluateBlockResultFunc = func(body hcl.Body, schema *configschema.Block, self addrs.Referenceable, keyData InstanceKeyEvalData) (cty.Value, hcl.Body, tfdiags.Diagnostics) { - if scope := c.EvaluationScopeScope; scope != nil { - // Fully-functional codepath. - var diags tfdiags.Diagnostics - body, diags = scope.ExpandBlock(body, schema) - if diags.HasErrors() { - return cty.DynamicVal, body, diags - } - val, evalDiags := c.EvaluationScopeScope.EvalBlock(body, schema) - diags = diags.Append(evalDiags) - if evalDiags.HasErrors() { - return cty.DynamicVal, body, diags - } - return val, body, diags - } - - // Fallback codepath supporting constant values only. - val, hclDiags := hcldec.Decode(body, schema.DecoderSpec(), nil) - return val, body, tfdiags.Diagnostics(nil).Append(hclDiags) - } - c.EvaluateExprResultFunc = func(expr hcl.Expression, wantType cty.Type, self addrs.Referenceable) (cty.Value, tfdiags.Diagnostics) { - if scope := c.EvaluationScopeScope; scope != nil { - // Fully-functional codepath. - return scope.EvalExpr(expr, wantType) - } - - // Fallback codepath supporting constant values only. - var diags tfdiags.Diagnostics - val, hclDiags := expr.Value(nil) - diags = diags.Append(hclDiags) - if hclDiags.HasErrors() { - return cty.DynamicVal, diags - } - var err error - val, err = convert.Convert(val, wantType) - if err != nil { - diags = diags.Append(err) - return cty.DynamicVal, diags - } - return val, diags - } -} - -func (c *MockEvalContext) EvaluationScope(self addrs.Referenceable, keyData InstanceKeyEvalData) *lang.Scope { - c.EvaluationScopeCalled = true - c.EvaluationScopeSelf = self - c.EvaluationScopeKeyData = keyData - return c.EvaluationScopeScope -} - -func (c *MockEvalContext) WithPath(path addrs.ModuleInstance) EvalContext { - newC := *c - newC.PathPath = path - return &newC -} - -func (c *MockEvalContext) Path() addrs.ModuleInstance { - c.PathCalled = true - return c.PathPath -} - -func (c *MockEvalContext) SetRootModuleArgument(addr addrs.InputVariable, v cty.Value) { - c.SetRootModuleArgumentCalled = true - c.SetRootModuleArgumentAddr = addr - c.SetRootModuleArgumentValue = v - if c.SetRootModuleArgumentFunc != nil { - c.SetRootModuleArgumentFunc(addr, v) - } -} - -func (c *MockEvalContext) SetModuleCallArgument(callAddr addrs.ModuleCallInstance, varAddr addrs.InputVariable, v cty.Value) { - c.SetModuleCallArgumentCalled = true - c.SetModuleCallArgumentModuleCall = callAddr - c.SetModuleCallArgumentVariable = varAddr - c.SetModuleCallArgumentValue = v - if c.SetModuleCallArgumentFunc != nil { - c.SetModuleCallArgumentFunc(callAddr, varAddr, v) - } -} - -func (c *MockEvalContext) GetVariableValue(addr addrs.AbsInputVariableInstance) cty.Value { - c.GetVariableValueCalled = true - c.GetVariableValueAddr = addr - if c.GetVariableValueFunc != nil { - return c.GetVariableValueFunc(addr) - } - return c.GetVariableValueValue -} - -func (c *MockEvalContext) Changes() *plans.ChangesSync { - c.ChangesCalled = true - return c.ChangesChanges -} - -func (c *MockEvalContext) State() *states.SyncState { - c.StateCalled = true - return c.StateState -} - -func (c *MockEvalContext) Checks() *checks.State { - c.ChecksCalled = true - return c.ChecksState -} - -func (c *MockEvalContext) RefreshState() *states.SyncState { - c.RefreshStateCalled = true - return c.RefreshStateState -} - -func (c *MockEvalContext) PrevRunState() *states.SyncState { - c.PrevRunStateCalled = true - return c.PrevRunStateState -} - -func (c *MockEvalContext) MoveResults() refactoring.MoveResults { - c.MoveResultsCalled = true - return c.MoveResultsResults -} - -func (c *MockEvalContext) InstanceExpander() *instances.Expander { - c.InstanceExpanderCalled = true - return c.InstanceExpanderExpander -} diff --git a/internal/terraform/eval_count.go b/internal/terraform/eval_count.go deleted file mode 100644 index d4ab1a998f60..000000000000 --- a/internal/terraform/eval_count.go +++ /dev/null @@ -1,107 +0,0 @@ -package terraform - -import ( - "fmt" - - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/tfdiags" - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/gocty" -) - -// evaluateCountExpression is our standard mechanism for interpreting an -// expression given for a "count" argument on a resource or a module. This -// should be called during expansion in order to determine the final count -// value. -// -// evaluateCountExpression differs from evaluateCountExpressionValue by -// returning an error if the count value is not known, and converting the -// cty.Value to an integer. -func evaluateCountExpression(expr hcl.Expression, ctx EvalContext) (int, tfdiags.Diagnostics) { - countVal, diags := evaluateCountExpressionValue(expr, ctx) - if !countVal.IsKnown() { - // Currently this is a rather bad outcome from a UX standpoint, since we have - // no real mechanism to deal with this situation and all we can do is produce - // an error message. - // FIXME: In future, implement a built-in mechanism for deferring changes that - // can't yet be predicted, and use it to guide the user through several - // plan/apply steps until the desired configuration is eventually reached. - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid count argument", - Detail: `The "count" value depends on resource attributes that cannot be determined until apply, so Terraform cannot predict how many instances will be created. To work around this, use the -target argument to first apply only the resources that the count depends on.`, - Subject: expr.Range().Ptr(), - - // TODO: Also populate Expression and EvalContext in here, but - // we can't easily do that right now because the hcl.EvalContext - // (which is not the same as the ctx we have in scope here) is - // hidden away inside evaluateCountExpressionValue. - Extra: diagnosticCausedByUnknown(true), - }) - } - - if countVal.IsNull() || !countVal.IsKnown() { - return -1, diags - } - - count, _ := countVal.AsBigFloat().Int64() - return int(count), diags -} - -// evaluateCountExpressionValue is like evaluateCountExpression -// except that it returns a cty.Value which must be a cty.Number and can be -// unknown. -func evaluateCountExpressionValue(expr hcl.Expression, ctx EvalContext) (cty.Value, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - nullCount := cty.NullVal(cty.Number) - if expr == nil { - return nullCount, nil - } - - countVal, countDiags := ctx.EvaluateExpr(expr, cty.Number, nil) - diags = diags.Append(countDiags) - if diags.HasErrors() { - return nullCount, diags - } - - // Unmark the count value, sensitive values are allowed in count but not for_each, - // as using it here will not disclose the sensitive value - countVal, _ = countVal.Unmark() - - switch { - case countVal.IsNull(): - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid count argument", - Detail: `The given "count" argument value is null. An integer is required.`, - Subject: expr.Range().Ptr(), - }) - return nullCount, diags - - case !countVal.IsKnown(): - return cty.UnknownVal(cty.Number), diags - } - - var count int - err := gocty.FromCtyValue(countVal, &count) - if err != nil { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid count argument", - Detail: fmt.Sprintf(`The given "count" argument value is unsuitable: %s.`, err), - Subject: expr.Range().Ptr(), - }) - return nullCount, diags - } - if count < 0 { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid count argument", - Detail: `The given "count" argument value is unsuitable: must be greater than or equal to zero.`, - Subject: expr.Range().Ptr(), - }) - return nullCount, diags - } - - return countVal, diags -} diff --git a/internal/terraform/eval_count_test.go b/internal/terraform/eval_count_test.go deleted file mode 100644 index 8d3a51b48813..000000000000 --- a/internal/terraform/eval_count_test.go +++ /dev/null @@ -1,46 +0,0 @@ -package terraform - -import ( - "reflect" - "testing" - - "github.com/davecgh/go-spew/spew" - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/hcl/v2/hcltest" - "github.com/hashicorp/terraform/internal/lang/marks" - "github.com/zclconf/go-cty/cty" -) - -func TestEvaluateCountExpression(t *testing.T) { - tests := map[string]struct { - Expr hcl.Expression - Count int - }{ - "zero": { - hcltest.MockExprLiteral(cty.NumberIntVal(0)), - 0, - }, - "expression with marked value": { - hcltest.MockExprLiteral(cty.NumberIntVal(8).Mark(marks.Sensitive)), - 8, - }, - } - for name, test := range tests { - t.Run(name, func(t *testing.T) { - ctx := &MockEvalContext{} - ctx.installSimpleEval() - countVal, diags := evaluateCountExpression(test.Expr, ctx) - - if len(diags) != 0 { - t.Errorf("unexpected diagnostics %s", spew.Sdump(diags)) - } - - if !reflect.DeepEqual(countVal, test.Count) { - t.Errorf( - "wrong map value\ngot: %swant: %s", - spew.Sdump(countVal), spew.Sdump(test.Count), - ) - } - }) - } -} diff --git a/internal/terraform/eval_for_each.go b/internal/terraform/eval_for_each.go deleted file mode 100644 index 3c80ebff01d3..000000000000 --- a/internal/terraform/eval_for_each.go +++ /dev/null @@ -1,193 +0,0 @@ -package terraform - -import ( - "fmt" - - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/lang" - "github.com/hashicorp/terraform/internal/lang/marks" - "github.com/hashicorp/terraform/internal/tfdiags" - "github.com/zclconf/go-cty/cty" -) - -// evaluateForEachExpression is our standard mechanism for interpreting an -// expression given for a "for_each" argument on a resource or a module. This -// should be called during expansion in order to determine the final keys and -// values. -// -// evaluateForEachExpression differs from evaluateForEachExpressionValue by -// returning an error if the count value is not known, and converting the -// cty.Value to a map[string]cty.Value for compatibility with other calls. -func evaluateForEachExpression(expr hcl.Expression, ctx EvalContext) (forEach map[string]cty.Value, diags tfdiags.Diagnostics) { - forEachVal, diags := evaluateForEachExpressionValue(expr, ctx, false) - // forEachVal might be unknown, but if it is then there should already - // be an error about it in diags, which we'll return below. - - if forEachVal.IsNull() || !forEachVal.IsKnown() || markSafeLengthInt(forEachVal) == 0 { - // we check length, because an empty set return a nil map - return map[string]cty.Value{}, diags - } - - return forEachVal.AsValueMap(), diags -} - -// evaluateForEachExpressionValue is like evaluateForEachExpression -// except that it returns a cty.Value map or set which can be unknown. -func evaluateForEachExpressionValue(expr hcl.Expression, ctx EvalContext, allowUnknown bool) (cty.Value, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - nullMap := cty.NullVal(cty.Map(cty.DynamicPseudoType)) - - if expr == nil { - return nullMap, diags - } - - refs, moreDiags := lang.ReferencesInExpr(expr) - diags = diags.Append(moreDiags) - scope := ctx.EvaluationScope(nil, EvalDataForNoInstanceKey) - var hclCtx *hcl.EvalContext - if scope != nil { - hclCtx, moreDiags = scope.EvalContext(refs) - } else { - // This shouldn't happen in real code, but it can unfortunately arise - // in unit tests due to incompletely-implemented mocks. :( - hclCtx = &hcl.EvalContext{} - } - diags = diags.Append(moreDiags) - if diags.HasErrors() { // Can't continue if we don't even have a valid scope - return nullMap, diags - } - - forEachVal, forEachDiags := expr.Value(hclCtx) - diags = diags.Append(forEachDiags) - - // If a whole map is marked, or a set contains marked values (which means the set is then marked) - // give an error diagnostic as this value cannot be used in for_each - if forEachVal.HasMark(marks.Sensitive) { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid for_each argument", - Detail: "Sensitive values, or values derived from sensitive values, cannot be used as for_each arguments. If used, the sensitive value could be exposed as a resource instance key.", - Subject: expr.Range().Ptr(), - Expression: expr, - EvalContext: hclCtx, - Extra: diagnosticCausedBySensitive(true), - }) - } - - if diags.HasErrors() { - return nullMap, diags - } - ty := forEachVal.Type() - - const errInvalidUnknownDetailMap = "The \"for_each\" map includes keys derived from resource attributes that cannot be determined until apply, and so Terraform cannot determine the full set of keys that will identify the instances of this resource.\n\nWhen working with unknown values in for_each, it's better to define the map keys statically in your configuration and place apply-time results only in the map values.\n\nAlternatively, you could use the -target planning option to first apply only the resources that the for_each value depends on, and then apply a second time to fully converge." - const errInvalidUnknownDetailSet = "The \"for_each\" set includes values derived from resource attributes that cannot be determined until apply, and so Terraform cannot determine the full set of keys that will identify the instances of this resource.\n\nWhen working with unknown values in for_each, it's better to use a map value where the keys are defined statically in your configuration and where only the values contain apply-time results.\n\nAlternatively, you could use the -target planning option to first apply only the resources that the for_each value depends on, and then apply a second time to fully converge." - - switch { - case forEachVal.IsNull(): - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid for_each argument", - Detail: `The given "for_each" argument value is unsuitable: the given "for_each" argument value is null. A map, or set of strings is allowed.`, - Subject: expr.Range().Ptr(), - Expression: expr, - EvalContext: hclCtx, - }) - return nullMap, diags - case !forEachVal.IsKnown(): - if !allowUnknown { - var detailMsg string - switch { - case ty.IsSetType(): - detailMsg = errInvalidUnknownDetailSet - default: - detailMsg = errInvalidUnknownDetailMap - } - - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid for_each argument", - Detail: detailMsg, - Subject: expr.Range().Ptr(), - Expression: expr, - EvalContext: hclCtx, - Extra: diagnosticCausedByUnknown(true), - }) - } - // ensure that we have a map, and not a DynamicValue - return cty.UnknownVal(cty.Map(cty.DynamicPseudoType)), diags - - case !(ty.IsMapType() || ty.IsSetType() || ty.IsObjectType()): - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid for_each argument", - Detail: fmt.Sprintf(`The given "for_each" argument value is unsuitable: the "for_each" argument must be a map, or set of strings, and you have provided a value of type %s.`, ty.FriendlyName()), - Subject: expr.Range().Ptr(), - Expression: expr, - EvalContext: hclCtx, - }) - return nullMap, diags - - case markSafeLengthInt(forEachVal) == 0: - // If the map is empty ({}), return an empty map, because cty will - // return nil when representing {} AsValueMap. This also covers an empty - // set (toset([])) - return forEachVal, diags - } - - if ty.IsSetType() { - // since we can't use a set values that are unknown, we treat the - // entire set as unknown - if !forEachVal.IsWhollyKnown() { - if !allowUnknown { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid for_each argument", - Detail: errInvalidUnknownDetailSet, - Subject: expr.Range().Ptr(), - Expression: expr, - EvalContext: hclCtx, - Extra: diagnosticCausedByUnknown(true), - }) - } - return cty.UnknownVal(ty), diags - } - - if ty.ElementType() != cty.String { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid for_each set argument", - Detail: fmt.Sprintf(`The given "for_each" argument value is unsuitable: "for_each" supports maps and sets of strings, but you have provided a set containing type %s.`, forEachVal.Type().ElementType().FriendlyName()), - Subject: expr.Range().Ptr(), - Expression: expr, - EvalContext: hclCtx, - }) - return cty.NullVal(ty), diags - } - - // A set of strings may contain null, which makes it impossible to - // convert to a map, so we must return an error - it := forEachVal.ElementIterator() - for it.Next() { - item, _ := it.Element() - if item.IsNull() { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid for_each set argument", - Detail: `The given "for_each" argument value is unsuitable: "for_each" sets must not contain null values.`, - Subject: expr.Range().Ptr(), - Expression: expr, - EvalContext: hclCtx, - }) - return cty.NullVal(ty), diags - } - } - } - - return forEachVal, nil -} - -// markSafeLengthInt allows calling LengthInt on marked values safely -func markSafeLengthInt(val cty.Value) int { - v, _ := val.UnmarkDeep() - return v.LengthInt() -} diff --git a/internal/terraform/eval_for_each_test.go b/internal/terraform/eval_for_each_test.go deleted file mode 100644 index 05dba9cabc46..000000000000 --- a/internal/terraform/eval_for_each_test.go +++ /dev/null @@ -1,232 +0,0 @@ -package terraform - -import ( - "reflect" - "strings" - "testing" - - "github.com/davecgh/go-spew/spew" - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/hcl/v2/hcltest" - "github.com/hashicorp/terraform/internal/lang/marks" - "github.com/hashicorp/terraform/internal/tfdiags" - "github.com/zclconf/go-cty/cty" -) - -func TestEvaluateForEachExpression_valid(t *testing.T) { - tests := map[string]struct { - Expr hcl.Expression - ForEachMap map[string]cty.Value - }{ - "empty set": { - hcltest.MockExprLiteral(cty.SetValEmpty(cty.String)), - map[string]cty.Value{}, - }, - "multi-value string set": { - hcltest.MockExprLiteral(cty.SetVal([]cty.Value{cty.StringVal("a"), cty.StringVal("b")})), - map[string]cty.Value{ - "a": cty.StringVal("a"), - "b": cty.StringVal("b"), - }, - }, - "empty map": { - hcltest.MockExprLiteral(cty.MapValEmpty(cty.Bool)), - map[string]cty.Value{}, - }, - "map": { - hcltest.MockExprLiteral(cty.MapVal(map[string]cty.Value{ - "a": cty.BoolVal(true), - "b": cty.BoolVal(false), - })), - map[string]cty.Value{ - "a": cty.BoolVal(true), - "b": cty.BoolVal(false), - }, - }, - "map containing unknown values": { - hcltest.MockExprLiteral(cty.MapVal(map[string]cty.Value{ - "a": cty.UnknownVal(cty.Bool), - "b": cty.UnknownVal(cty.Bool), - })), - map[string]cty.Value{ - "a": cty.UnknownVal(cty.Bool), - "b": cty.UnknownVal(cty.Bool), - }, - }, - "map containing sensitive values, but strings are literal": { - hcltest.MockExprLiteral(cty.MapVal(map[string]cty.Value{ - "a": cty.BoolVal(true).Mark(marks.Sensitive), - "b": cty.BoolVal(false), - })), - map[string]cty.Value{ - "a": cty.BoolVal(true).Mark(marks.Sensitive), - "b": cty.BoolVal(false), - }, - }, - } - - for name, test := range tests { - t.Run(name, func(t *testing.T) { - ctx := &MockEvalContext{} - ctx.installSimpleEval() - forEachMap, diags := evaluateForEachExpression(test.Expr, ctx) - - if len(diags) != 0 { - t.Errorf("unexpected diagnostics %s", spew.Sdump(diags)) - } - - if !reflect.DeepEqual(forEachMap, test.ForEachMap) { - t.Errorf( - "wrong map value\ngot: %swant: %s", - spew.Sdump(forEachMap), spew.Sdump(test.ForEachMap), - ) - } - - }) - } -} - -func TestEvaluateForEachExpression_errors(t *testing.T) { - tests := map[string]struct { - Expr hcl.Expression - Summary, DetailSubstring string - CausedByUnknown, CausedBySensitive bool - }{ - "null set": { - hcltest.MockExprLiteral(cty.NullVal(cty.Set(cty.String))), - "Invalid for_each argument", - `the given "for_each" argument value is null`, - false, false, - }, - "string": { - hcltest.MockExprLiteral(cty.StringVal("i am definitely a set")), - "Invalid for_each argument", - "must be a map, or set of strings, and you have provided a value of type string", - false, false, - }, - "list": { - hcltest.MockExprLiteral(cty.ListVal([]cty.Value{cty.StringVal("a"), cty.StringVal("a")})), - "Invalid for_each argument", - "must be a map, or set of strings, and you have provided a value of type list", - false, false, - }, - "tuple": { - hcltest.MockExprLiteral(cty.TupleVal([]cty.Value{cty.StringVal("a"), cty.StringVal("b")})), - "Invalid for_each argument", - "must be a map, or set of strings, and you have provided a value of type tuple", - false, false, - }, - "unknown string set": { - hcltest.MockExprLiteral(cty.UnknownVal(cty.Set(cty.String))), - "Invalid for_each argument", - "set includes values derived from resource attributes that cannot be determined until apply", - true, false, - }, - "unknown map": { - hcltest.MockExprLiteral(cty.UnknownVal(cty.Map(cty.Bool))), - "Invalid for_each argument", - "map includes keys derived from resource attributes that cannot be determined until apply", - true, false, - }, - "marked map": { - hcltest.MockExprLiteral(cty.MapVal(map[string]cty.Value{ - "a": cty.BoolVal(true), - "b": cty.BoolVal(false), - }).Mark(marks.Sensitive)), - "Invalid for_each argument", - "Sensitive values, or values derived from sensitive values, cannot be used as for_each arguments. If used, the sensitive value could be exposed as a resource instance key.", - false, true, - }, - "set containing booleans": { - hcltest.MockExprLiteral(cty.SetVal([]cty.Value{cty.BoolVal(true)})), - "Invalid for_each set argument", - "supports maps and sets of strings, but you have provided a set containing type bool", - false, false, - }, - "set containing null": { - hcltest.MockExprLiteral(cty.SetVal([]cty.Value{cty.NullVal(cty.String)})), - "Invalid for_each set argument", - "must not contain null values", - false, false, - }, - "set containing unknown value": { - hcltest.MockExprLiteral(cty.SetVal([]cty.Value{cty.UnknownVal(cty.String)})), - "Invalid for_each argument", - "set includes values derived from resource attributes that cannot be determined until apply", - true, false, - }, - "set containing dynamic unknown value": { - hcltest.MockExprLiteral(cty.SetVal([]cty.Value{cty.UnknownVal(cty.DynamicPseudoType)})), - "Invalid for_each argument", - "set includes values derived from resource attributes that cannot be determined until apply", - true, false, - }, - "set containing marked values": { - hcltest.MockExprLiteral(cty.SetVal([]cty.Value{cty.StringVal("beep").Mark(marks.Sensitive), cty.StringVal("boop")})), - "Invalid for_each argument", - "Sensitive values, or values derived from sensitive values, cannot be used as for_each arguments. If used, the sensitive value could be exposed as a resource instance key.", - false, true, - }, - } - - for name, test := range tests { - t.Run(name, func(t *testing.T) { - ctx := &MockEvalContext{} - ctx.installSimpleEval() - _, diags := evaluateForEachExpression(test.Expr, ctx) - - if len(diags) != 1 { - t.Fatalf("got %d diagnostics; want 1", diags) - } - if got, want := diags[0].Severity(), tfdiags.Error; got != want { - t.Errorf("wrong diagnostic severity %#v; want %#v", got, want) - } - if got, want := diags[0].Description().Summary, test.Summary; got != want { - t.Errorf("wrong diagnostic summary\ngot: %s\nwant: %s", got, want) - } - if got, want := diags[0].Description().Detail, test.DetailSubstring; !strings.Contains(got, want) { - t.Errorf("wrong diagnostic detail\ngot: %s\nwant substring: %s", got, want) - } - if fromExpr := diags[0].FromExpr(); fromExpr != nil { - if fromExpr.Expression == nil { - t.Errorf("diagnostic does not refer to an expression") - } - if fromExpr.EvalContext == nil { - t.Errorf("diagnostic does not refer to an EvalContext") - } - } else { - t.Errorf("diagnostic does not support FromExpr\ngot: %s", spew.Sdump(diags[0])) - } - - if got, want := tfdiags.DiagnosticCausedByUnknown(diags[0]), test.CausedByUnknown; got != want { - t.Errorf("wrong result from tfdiags.DiagnosticCausedByUnknown\ngot: %#v\nwant: %#v", got, want) - } - if got, want := tfdiags.DiagnosticCausedBySensitive(diags[0]), test.CausedBySensitive; got != want { - t.Errorf("wrong result from tfdiags.DiagnosticCausedBySensitive\ngot: %#v\nwant: %#v", got, want) - } - }) - } -} - -func TestEvaluateForEachExpressionKnown(t *testing.T) { - tests := map[string]hcl.Expression{ - "unknown string set": hcltest.MockExprLiteral(cty.UnknownVal(cty.Set(cty.String))), - "unknown map": hcltest.MockExprLiteral(cty.UnknownVal(cty.Map(cty.Bool))), - } - - for name, expr := range tests { - t.Run(name, func(t *testing.T) { - ctx := &MockEvalContext{} - ctx.installSimpleEval() - forEachVal, diags := evaluateForEachExpressionValue(expr, ctx, true) - - if len(diags) != 0 { - t.Errorf("unexpected diagnostics %s", spew.Sdump(diags)) - } - - if forEachVal.IsKnown() { - t.Error("got known, want unknown") - } - }) - } -} diff --git a/internal/terraform/eval_provider.go b/internal/terraform/eval_provider.go deleted file mode 100644 index a97f347e404f..000000000000 --- a/internal/terraform/eval_provider.go +++ /dev/null @@ -1,59 +0,0 @@ -package terraform - -import ( - "fmt" - "log" - - "github.com/hashicorp/hcl/v2" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/providers" -) - -func buildProviderConfig(ctx EvalContext, addr addrs.AbsProviderConfig, config *configs.Provider) hcl.Body { - var configBody hcl.Body - if config != nil { - configBody = config.Config - } - - var inputBody hcl.Body - inputConfig := ctx.ProviderInput(addr) - if len(inputConfig) > 0 { - inputBody = configs.SynthBody("", inputConfig) - } - - switch { - case configBody != nil && inputBody != nil: - log.Printf("[TRACE] buildProviderConfig for %s: merging explicit config and input", addr) - return hcl.MergeBodies([]hcl.Body{inputBody, configBody}) - case configBody != nil: - log.Printf("[TRACE] buildProviderConfig for %s: using explicit config only", addr) - return configBody - case inputBody != nil: - log.Printf("[TRACE] buildProviderConfig for %s: using input only", addr) - return inputBody - default: - log.Printf("[TRACE] buildProviderConfig for %s: no configuration at all", addr) - return hcl.EmptyBody() - } -} - -// getProvider returns the providers.Interface and schema for a given provider. -func getProvider(ctx EvalContext, addr addrs.AbsProviderConfig) (providers.Interface, *ProviderSchema, error) { - if addr.Provider.Type == "" { - // Should never happen - panic("GetProvider used with uninitialized provider configuration address") - } - provider := ctx.Provider(addr) - if provider == nil { - return nil, &ProviderSchema{}, fmt.Errorf("provider %s not initialized", addr) - } - // Not all callers require a schema, so we will leave checking for a nil - // schema to the callers. - schema, err := ctx.ProviderSchema(addr) - if err != nil { - return nil, &ProviderSchema{}, fmt.Errorf("failed to read schema for provider %s: %w", addr, err) - } - return provider, schema, nil -} diff --git a/internal/terraform/eval_provider_test.go b/internal/terraform/eval_provider_test.go deleted file mode 100644 index 0a1aeca703e9..000000000000 --- a/internal/terraform/eval_provider_test.go +++ /dev/null @@ -1,55 +0,0 @@ -package terraform - -import ( - "testing" - - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/zclconf/go-cty/cty" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configschema" -) - -func TestBuildProviderConfig(t *testing.T) { - configBody := configs.SynthBody("", map[string]cty.Value{ - "set_in_config": cty.StringVal("config"), - }) - providerAddr := addrs.AbsProviderConfig{ - Module: addrs.RootModule, - Provider: addrs.NewDefaultProvider("foo"), - } - - ctx := &MockEvalContext{ - // The input values map is expected to contain only keys that aren't - // already present in the config, since we skip prompting for - // attributes that are already set. - ProviderInputValues: map[string]cty.Value{ - "set_by_input": cty.StringVal("input"), - }, - } - gotBody := buildProviderConfig(ctx, providerAddr, &configs.Provider{ - Name: "foo", - Config: configBody, - }) - - schema := &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "set_in_config": {Type: cty.String, Optional: true}, - "set_by_input": {Type: cty.String, Optional: true}, - }, - } - got, diags := hcldec.Decode(gotBody, schema.DecoderSpec(), nil) - if diags.HasErrors() { - t.Fatalf("body decode failed: %s", diags.Error()) - } - - // We expect the provider config with the added input value - want := cty.ObjectVal(map[string]cty.Value{ - "set_in_config": cty.StringVal("config"), - "set_by_input": cty.StringVal("input"), - }) - if !got.RawEquals(want) { - t.Fatalf("incorrect merged config\ngot: %#v\nwant: %#v", got, want) - } -} diff --git a/internal/terraform/eval_variable.go b/internal/terraform/eval_variable.go deleted file mode 100644 index 8878886383e4..000000000000 --- a/internal/terraform/eval_variable.go +++ /dev/null @@ -1,394 +0,0 @@ -package terraform - -import ( - "fmt" - "log" - "strings" - - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/hcl/v2/gohcl" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/lang/marks" - "github.com/hashicorp/terraform/internal/tfdiags" - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/convert" -) - -func prepareFinalInputVariableValue(addr addrs.AbsInputVariableInstance, raw *InputValue, cfg *configs.Variable) (cty.Value, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - - convertTy := cfg.ConstraintType - log.Printf("[TRACE] prepareFinalInputVariableValue: preparing %s", addr) - - var defaultVal cty.Value - if cfg.Default != cty.NilVal { - log.Printf("[TRACE] prepareFinalInputVariableValue: %s has a default value", addr) - var err error - defaultVal, err = convert.Convert(cfg.Default, convertTy) - if err != nil { - // Validation of the declaration should typically catch this, - // but we'll check it here too to be robust. - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid default value for module argument", - Detail: fmt.Sprintf( - "The default value for variable %q is incompatible with its type constraint: %s.", - cfg.Name, err, - ), - Subject: &cfg.DeclRange, - }) - // We'll return a placeholder unknown value to avoid producing - // redundant downstream errors. - return cty.UnknownVal(cfg.Type), diags - } - } - - var sourceRange tfdiags.SourceRange - var nonFileSource string - if raw.HasSourceRange() { - sourceRange = raw.SourceRange - } else { - // If the value came from a place that isn't a file and thus doesn't - // have its own source range, we'll use the declaration range as - // our source range and generate some slightly different error - // messages. - sourceRange = tfdiags.SourceRangeFromHCL(cfg.DeclRange) - switch raw.SourceType { - case ValueFromCLIArg: - nonFileSource = fmt.Sprintf("set using -var=\"%s=...\"", addr.Variable.Name) - case ValueFromEnvVar: - nonFileSource = fmt.Sprintf("set using the TF_VAR_%s environment variable", addr.Variable.Name) - case ValueFromInput: - nonFileSource = "set using an interactive prompt" - default: - nonFileSource = "set from outside of the configuration" - } - } - - given := raw.Value - if given == cty.NilVal { // The variable wasn't set at all (even to null) - log.Printf("[TRACE] prepareFinalInputVariableValue: %s has no defined value", addr) - if cfg.Required() { - // NOTE: The CLI layer typically checks for itself whether all of - // the required _root_ module variables are set, which would - // mask this error with a more specific one that refers to the - // CLI features for setting such variables. We can get here for - // child module variables, though. - log.Printf("[ERROR] prepareFinalInputVariableValue: %s is required but is not set", addr) - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: `Required variable not set`, - Detail: fmt.Sprintf(`The variable %q is required, but is not set.`, addr.Variable.Name), - Subject: cfg.DeclRange.Ptr(), - }) - // We'll return a placeholder unknown value to avoid producing - // redundant downstream errors. - return cty.UnknownVal(cfg.Type), diags - } - - given = defaultVal // must be set, because we checked above that the variable isn't required - } - - // Apply defaults from the variable's type constraint to the converted value, - // unless the converted value is null. We do not apply defaults to top-level - // null values, as doing so could prevent assigning null to a nullable - // variable. - if cfg.TypeDefaults != nil && !given.IsNull() { - given = cfg.TypeDefaults.Apply(given) - } - - val, err := convert.Convert(given, convertTy) - if err != nil { - log.Printf("[ERROR] prepareFinalInputVariableValue: %s has unsuitable type\n got: %s\n want: %s", addr, given.Type(), convertTy) - var detail string - var subject *hcl.Range - if nonFileSource != "" { - detail = fmt.Sprintf( - "Unsuitable value for %s %s: %s.", - addr, nonFileSource, err, - ) - subject = cfg.DeclRange.Ptr() - } else { - detail = fmt.Sprintf( - "The given value is not suitable for %s declared at %s: %s.", - addr, cfg.DeclRange.String(), err, - ) - subject = sourceRange.ToHCL().Ptr() - - // In some workflows, the operator running terraform does not have access to the variables - // themselves. They are for example stored in encrypted files that will be used by the CI toolset - // and not by the operator directly. In such a case, the failing secret value should not be - // displayed to the operator - if cfg.Sensitive { - detail = fmt.Sprintf( - "The given value is not suitable for %s, which is sensitive: %s. Invalid value defined at %s.", - addr, err, sourceRange.ToHCL(), - ) - subject = cfg.DeclRange.Ptr() - } - } - - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid value for input variable", - Detail: detail, - Subject: subject, - }) - // We'll return a placeholder unknown value to avoid producing - // redundant downstream errors. - return cty.UnknownVal(cfg.Type), diags - } - - // By the time we get here, we know: - // - val matches the variable's type constraint - // - val is definitely not cty.NilVal, but might be a null value if the given was already null. - // - // That means we just need to handle the case where the value is null, - // which might mean we need to use the default value, or produce an error. - // - // For historical reasons we do this only for a "non-nullable" variable. - // Nullable variables just appear as null if they were set to null, - // regardless of any default value. - if val.IsNull() && !cfg.Nullable { - log.Printf("[TRACE] prepareFinalInputVariableValue: %s is defined as null", addr) - if defaultVal != cty.NilVal { - val = defaultVal - } else { - log.Printf("[ERROR] prepareFinalInputVariableValue: %s is non-nullable but set to null, and is required", addr) - if nonFileSource != "" { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: `Required variable not set`, - Detail: fmt.Sprintf( - "Unsuitable value for %s %s: required variable may not be set to null.", - addr, nonFileSource, - ), - Subject: cfg.DeclRange.Ptr(), - }) - } else { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: `Required variable not set`, - Detail: fmt.Sprintf( - "The given value is not suitable for %s defined at %s: required variable may not be set to null.", - addr, cfg.DeclRange.String(), - ), - Subject: sourceRange.ToHCL().Ptr(), - }) - } - // Stub out our return value so that the semantic checker doesn't - // produce redundant downstream errors. - val = cty.UnknownVal(cfg.Type) - } - } - - return val, diags -} - -// evalVariableValidations ensures that all of the configured custom validations -// for a variable are passing. -// -// This must be used only after any side-effects that make the value of the -// variable available for use in expression evaluation, such as -// EvalModuleCallArgument for variables in descendent modules. -func evalVariableValidations(addr addrs.AbsInputVariableInstance, config *configs.Variable, expr hcl.Expression, ctx EvalContext) (diags tfdiags.Diagnostics) { - if config == nil || len(config.Validations) == 0 { - log.Printf("[TRACE] evalVariableValidations: no validation rules declared for %s, so skipping", addr) - return nil - } - log.Printf("[TRACE] evalVariableValidations: validating %s", addr) - - // Variable nodes evaluate in the parent module to where they were declared - // because the value expression (n.Expr, if set) comes from the calling - // "module" block in the parent module. - // - // Validation expressions are statically validated (during configuration - // loading) to refer only to the variable being validated, so we can - // bypass our usual evaluation machinery here and just produce a minimal - // evaluation context containing just the required value, and thus avoid - // the problem that ctx's evaluation functions refer to the wrong module. - val := ctx.GetVariableValue(addr) - if val == cty.NilVal { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "No final value for variable", - Detail: fmt.Sprintf("Terraform doesn't have a final value for %s during validation. This is a bug in Terraform; please report it!", addr), - }) - return diags - } - hclCtx := &hcl.EvalContext{ - Variables: map[string]cty.Value{ - "var": cty.ObjectVal(map[string]cty.Value{ - config.Name: val, - }), - }, - Functions: ctx.EvaluationScope(nil, EvalDataForNoInstanceKey).Functions(), - } - - for _, validation := range config.Validations { - const errInvalidCondition = "Invalid variable validation result" - const errInvalidValue = "Invalid value for variable" - var ruleDiags tfdiags.Diagnostics - - result, moreDiags := validation.Condition.Value(hclCtx) - ruleDiags = ruleDiags.Append(moreDiags) - errorValue, errorDiags := validation.ErrorMessage.Value(hclCtx) - - // The following error handling is a workaround to preserve backwards - // compatibility. Due to an implementation quirk, all prior versions of - // Terraform would treat error messages specified using JSON - // configuration syntax (.tf.json) as string literals, even if they - // contained the "${" template expression operator. This behaviour did - // not match that of HCL configuration syntax, where a template - // expression would result in a validation error. - // - // As a result, users writing or generating JSON configuration syntax - // may have specified error messages which are invalid template - // expressions. As we add support for error message expressions, we are - // unable to perfectly distinguish between these two cases. - // - // To ensure that we don't break backwards compatibility, we have the - // below fallback logic if the error message fails to evaluate. This - // should only have any effect for JSON configurations. The gohcl - // DecodeExpression function behaves differently when the source of the - // expression is a JSON configuration file and a nil context is passed. - if errorDiags.HasErrors() { - // Attempt to decode the expression as a string literal. Passing - // nil as the context forces a JSON syntax string value to be - // interpreted as a string literal. - var errorString string - moreErrorDiags := gohcl.DecodeExpression(validation.ErrorMessage, nil, &errorString) - if !moreErrorDiags.HasErrors() { - // Decoding succeeded, meaning that this is a JSON syntax - // string value. We rewrap that as a cty value to allow later - // decoding to succeed. - errorValue = cty.StringVal(errorString) - - // This warning diagnostic explains this odd behaviour, while - // giving us an escape hatch to change this to a hard failure - // in some future Terraform 1.x version. - errorDiags = hcl.Diagnostics{ - &hcl.Diagnostic{ - Severity: hcl.DiagWarning, - Summary: "Validation error message expression is invalid", - Detail: fmt.Sprintf("The error message provided could not be evaluated as an expression, so Terraform is interpreting it as a string literal.\n\nIn future versions of Terraform, this will be considered an error. Please file a GitHub issue if this would break your workflow.\n\n%s", errorDiags.Error()), - Subject: validation.ErrorMessage.Range().Ptr(), - Context: validation.DeclRange.Ptr(), - Expression: validation.ErrorMessage, - EvalContext: hclCtx, - }, - } - } - - // We want to either report the original diagnostics if the - // fallback failed, or the warning generated above if it succeeded. - ruleDiags = ruleDiags.Append(errorDiags) - } - - diags = diags.Append(ruleDiags) - - if ruleDiags.HasErrors() { - log.Printf("[TRACE] evalVariableValidations: %s rule %s check rule evaluation failed: %s", addr, validation.DeclRange, ruleDiags.Err().Error()) - } - if !result.IsKnown() { - log.Printf("[TRACE] evalVariableValidations: %s rule %s condition value is unknown, so skipping validation for now", addr, validation.DeclRange) - continue // We'll wait until we've learned more, then. - } - if result.IsNull() { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: errInvalidCondition, - Detail: "Validation condition expression must return either true or false, not null.", - Subject: validation.Condition.Range().Ptr(), - Expression: validation.Condition, - EvalContext: hclCtx, - }) - continue - } - var err error - result, err = convert.Convert(result, cty.Bool) - if err != nil { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: errInvalidCondition, - Detail: fmt.Sprintf("Invalid validation condition result value: %s.", tfdiags.FormatError(err)), - Subject: validation.Condition.Range().Ptr(), - Expression: validation.Condition, - EvalContext: hclCtx, - }) - continue - } - - // Validation condition may be marked if the input variable is bound to - // a sensitive value. This is irrelevant to the validation process, so - // we discard the marks now. - result, _ = result.Unmark() - - if result.True() { - continue - } - - var errorMessage string - if !errorDiags.HasErrors() && errorValue.IsKnown() && !errorValue.IsNull() { - var err error - errorValue, err = convert.Convert(errorValue, cty.String) - if err != nil { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid error message", - Detail: fmt.Sprintf("Unsuitable value for error message: %s.", tfdiags.FormatError(err)), - Subject: validation.ErrorMessage.Range().Ptr(), - Expression: validation.ErrorMessage, - EvalContext: hclCtx, - }) - } else { - if marks.Has(errorValue, marks.Sensitive) { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - - Summary: "Error message refers to sensitive values", - Detail: `The error expression used to explain this condition refers to sensitive values. Terraform will not display the resulting message. - -You can correct this by removing references to sensitive values, or by carefully using the nonsensitive() function if the expression will not reveal the sensitive data.`, - - Subject: validation.ErrorMessage.Range().Ptr(), - Expression: validation.ErrorMessage, - EvalContext: hclCtx, - }) - errorMessage = "The error message included a sensitive value, so it will not be displayed." - } else { - errorMessage = strings.TrimSpace(errorValue.AsString()) - } - } - } - if errorMessage == "" { - errorMessage = "Failed to evaluate condition error message." - } - - if expr != nil { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: errInvalidValue, - Detail: fmt.Sprintf("%s\n\nThis was checked by the validation rule at %s.", errorMessage, validation.DeclRange.String()), - Subject: expr.Range().Ptr(), - Expression: validation.Condition, - EvalContext: hclCtx, - }) - } else { - // Since we don't have a source expression for a root module - // variable, we'll just report the error from the perspective - // of the variable declaration itself. - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: errInvalidValue, - Detail: fmt.Sprintf("%s\n\nThis was checked by the validation rule at %s.", errorMessage, validation.DeclRange.String()), - Subject: config.DeclRange.Ptr(), - Expression: validation.Condition, - EvalContext: hclCtx, - }) - } - } - - return diags -} diff --git a/internal/terraform/eval_variable_test.go b/internal/terraform/eval_variable_test.go deleted file mode 100644 index 3821d8f8ca00..000000000000 --- a/internal/terraform/eval_variable_test.go +++ /dev/null @@ -1,1345 +0,0 @@ -package terraform - -import ( - "fmt" - "strings" - "testing" - - "github.com/hashicorp/hcl/v2" - "github.com/zclconf/go-cty/cty" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/lang" - "github.com/hashicorp/terraform/internal/lang/marks" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -func TestPrepareFinalInputVariableValue(t *testing.T) { - // This is just a concise way to define a bunch of *configs.Variable - // objects to use in our tests below. We're only going to decode this - // config, not fully evaluate it. - cfgSrc := ` - variable "nullable_required" { - } - variable "nullable_optional_default_string" { - default = "hello" - } - variable "nullable_optional_default_null" { - default = null - } - variable "constrained_string_nullable_required" { - type = string - } - variable "constrained_string_nullable_optional_default_string" { - type = string - default = "hello" - } - variable "constrained_string_nullable_optional_default_bool" { - type = string - default = true - } - variable "constrained_string_nullable_optional_default_null" { - type = string - default = null - } - variable "required" { - nullable = false - } - variable "optional_default_string" { - nullable = false - default = "hello" - } - variable "constrained_string_required" { - nullable = false - type = string - } - variable "constrained_string_optional_default_string" { - nullable = false - type = string - default = "hello" - } - variable "constrained_string_optional_default_bool" { - nullable = false - type = string - default = true - } - variable "constrained_string_sensitive_required" { - sensitive = true - nullable = false - type = string - } - variable "complex_type_with_nested_default_optional" { - type = set(object({ - name = string - schedules = set(object({ - name = string - cold_storage_after = optional(number, 10) - })) - })) - } - variable "complex_type_with_nested_complex_types" { - type = object({ - name = string - nested_object = object({ - name = string - value = optional(string, "foo") - }) - nested_object_with_default = optional(object({ - name = string - value = optional(string, "bar") - }), { - name = "nested_object_with_default" - }) - }) - } - // https://github.com/hashicorp/terraform/issues/32152 - // This variable was originally added to test that optional attribute - // metadata is stripped from empty default collections. Essentially, you - // should be able to mix and match custom and default values for the - // optional_list attribute. - variable "complex_type_with_empty_default_and_nested_optional" { - type = list(object({ - name = string - optional_list = optional(list(object({ - string = string - optional_string = optional(string) - })), []) - })) - } - // https://github.com/hashicorp/terraform/issues/32160#issuecomment-1302783910 - // These variables were added to test the specific use case from this - // GitHub comment. - variable "empty_object_with_optional_nested_object_with_optional_bool" { - type = object({ - thing = optional(object({ - flag = optional(bool, false) - })) - }) - default = {} - } - variable "populated_object_with_optional_nested_object_with_optional_bool" { - type = object({ - thing = optional(object({ - flag = optional(bool, false) - })) - }) - default = { - thing = {} - } - } - variable "empty_object_with_default_nested_object_with_optional_bool" { - type = object({ - thing = optional(object({ - flag = optional(bool, false) - }), {}) - }) - default = {} - } - // https://github.com/hashicorp/terraform/issues/32160 - // This variable was originally added to test that optional objects do - // get created containing only their defaults. Instead they should be - // left empty. We do not expect nested_object to be created just because - // optional_string has a default value. - variable "object_with_nested_object_with_required_and_optional_attributes" { - type = object({ - nested_object = optional(object({ - string = string - optional_string = optional(string, "optional") - })) - }) - } - // https://github.com/hashicorp/terraform/issues/32157 - // Similar to above, we want to see that merging combinations of the - // nested_object into a single collection doesn't crash because of - // inconsistent elements. - variable "list_with_nested_object_with_required_and_optional_attributes" { - type = list(object({ - nested_object = optional(object({ - string = string - optional_string = optional(string, "optional") - })) - })) - } - // https://github.com/hashicorp/terraform/issues/32109 - // This variable was originally introduced to test the behaviour of - // the dynamic type constraint. You should be able to use the 'any' - // constraint and introduce empty, null, and populated values into the - // list. - variable "list_with_nested_list_of_any" { - type = list(object({ - a = string - b = optional(list(any)) - })) - default = [ - { - a = "a" - }, - { - a = "b" - b = [1] - } - ] - } - // https://github.com/hashicorp/terraform/issues/32396 - // This variable was originally introduced to test the behaviour of the - // dynamic type constraint. You should be able to set primitive types in - // the list consistently. - variable "list_with_nested_collections_dynamic_with_default" { - type = list( - object({ - name = optional(string, "default") - taints = optional(list(map(any)), []) - }) - ) - } - // https://github.com/hashicorp/terraform/issues/32752 - // This variable was introduced to make sure the evaluation doesn't - // crash even when the types are wrong. - variable "invalid_nested_type" { - type = map( - object({ - rules = map( - object({ - destination_addresses = optional(list(string), []) - }) - ) - }) - ) - default = {} - } - ` - cfg := testModuleInline(t, map[string]string{ - "main.tf": cfgSrc, - }) - variableConfigs := cfg.Module.Variables - - // Because we loaded our pseudo-module from a temporary file, the - // declaration source ranges will have unpredictable filenames. We'll - // fix that here just to make things easier below. - for _, vc := range variableConfigs { - vc.DeclRange.Filename = "main.tf" - } - - tests := []struct { - varName string - given cty.Value - want cty.Value - wantErr string - }{ - // nullable_required - { - "nullable_required", - cty.NilVal, - cty.UnknownVal(cty.DynamicPseudoType), - `Required variable not set: The variable "nullable_required" is required, but is not set.`, - }, - { - "nullable_required", - cty.NullVal(cty.DynamicPseudoType), - cty.NullVal(cty.DynamicPseudoType), - ``, // "required" for a nullable variable means only that it must be set, even if it's set to null - }, - { - "nullable_required", - cty.StringVal("ahoy"), - cty.StringVal("ahoy"), - ``, - }, - { - "nullable_required", - cty.UnknownVal(cty.String), - cty.UnknownVal(cty.String), - ``, - }, - - // nullable_optional_default_string - { - "nullable_optional_default_string", - cty.NilVal, - cty.StringVal("hello"), // the declared default value - ``, - }, - { - "nullable_optional_default_string", - cty.NullVal(cty.DynamicPseudoType), - cty.NullVal(cty.DynamicPseudoType), // nullable variables can be really set to null, masking the default - ``, - }, - { - "nullable_optional_default_string", - cty.StringVal("ahoy"), - cty.StringVal("ahoy"), - ``, - }, - { - "nullable_optional_default_string", - cty.UnknownVal(cty.String), - cty.UnknownVal(cty.String), - ``, - }, - - // nullable_optional_default_null - { - "nullable_optional_default_null", - cty.NilVal, - cty.NullVal(cty.DynamicPseudoType), // the declared default value - ``, - }, - { - "nullable_optional_default_null", - cty.NullVal(cty.String), - cty.NullVal(cty.String), // nullable variables can be really set to null, masking the default - ``, - }, - { - "nullable_optional_default_null", - cty.StringVal("ahoy"), - cty.StringVal("ahoy"), - ``, - }, - { - "nullable_optional_default_null", - cty.UnknownVal(cty.String), - cty.UnknownVal(cty.String), - ``, - }, - - // constrained_string_nullable_required - { - "constrained_string_nullable_required", - cty.NilVal, - cty.UnknownVal(cty.String), - `Required variable not set: The variable "constrained_string_nullable_required" is required, but is not set.`, - }, - { - "constrained_string_nullable_required", - cty.NullVal(cty.DynamicPseudoType), - cty.NullVal(cty.String), // the null value still gets converted to match the type constraint - ``, // "required" for a nullable variable means only that it must be set, even if it's set to null - }, - { - "constrained_string_nullable_required", - cty.StringVal("ahoy"), - cty.StringVal("ahoy"), - ``, - }, - { - "constrained_string_nullable_required", - cty.UnknownVal(cty.String), - cty.UnknownVal(cty.String), - ``, - }, - - // constrained_string_nullable_optional_default_string - { - "constrained_string_nullable_optional_default_string", - cty.NilVal, - cty.StringVal("hello"), // the declared default value - ``, - }, - { - "constrained_string_nullable_optional_default_string", - cty.NullVal(cty.DynamicPseudoType), - cty.NullVal(cty.String), // nullable variables can be really set to null, masking the default - ``, - }, - { - "constrained_string_nullable_optional_default_string", - cty.StringVal("ahoy"), - cty.StringVal("ahoy"), - ``, - }, - { - "constrained_string_nullable_optional_default_string", - cty.UnknownVal(cty.String), - cty.UnknownVal(cty.String), - ``, - }, - - // constrained_string_nullable_optional_default_bool - { - "constrained_string_nullable_optional_default_bool", - cty.NilVal, - cty.StringVal("true"), // the declared default value, automatically converted to match type constraint - ``, - }, - { - "constrained_string_nullable_optional_default_bool", - cty.NullVal(cty.DynamicPseudoType), - cty.NullVal(cty.String), // nullable variables can be really set to null, masking the default - ``, - }, - { - "constrained_string_nullable_optional_default_bool", - cty.StringVal("ahoy"), - cty.StringVal("ahoy"), - ``, - }, - { - "constrained_string_nullable_optional_default_bool", - cty.UnknownVal(cty.String), - cty.UnknownVal(cty.String), - ``, - }, - - // constrained_string_nullable_optional_default_null - { - "constrained_string_nullable_optional_default_null", - cty.NilVal, - cty.NullVal(cty.String), - ``, - }, - { - "constrained_string_nullable_optional_default_null", - cty.NullVal(cty.DynamicPseudoType), - cty.NullVal(cty.String), - ``, - }, - { - "constrained_string_nullable_optional_default_null", - cty.StringVal("ahoy"), - cty.StringVal("ahoy"), - ``, - }, - { - "constrained_string_nullable_optional_default_null", - cty.UnknownVal(cty.String), - cty.UnknownVal(cty.String), - ``, - }, - - // required - { - "required", - cty.NilVal, - cty.UnknownVal(cty.DynamicPseudoType), - `Required variable not set: The variable "required" is required, but is not set.`, - }, - { - "required", - cty.NullVal(cty.DynamicPseudoType), - cty.UnknownVal(cty.DynamicPseudoType), - `Required variable not set: Unsuitable value for var.required set from outside of the configuration: required variable may not be set to null.`, - }, - { - "required", - cty.StringVal("ahoy"), - cty.StringVal("ahoy"), - ``, - }, - { - "required", - cty.UnknownVal(cty.String), - cty.UnknownVal(cty.String), - ``, - }, - - // optional_default_string - { - "optional_default_string", - cty.NilVal, - cty.StringVal("hello"), // the declared default value - ``, - }, - { - "optional_default_string", - cty.NullVal(cty.DynamicPseudoType), - cty.StringVal("hello"), // the declared default value - ``, - }, - { - "optional_default_string", - cty.StringVal("ahoy"), - cty.StringVal("ahoy"), - ``, - }, - { - "optional_default_string", - cty.UnknownVal(cty.String), - cty.UnknownVal(cty.String), - ``, - }, - - // constrained_string_required - { - "constrained_string_required", - cty.NilVal, - cty.UnknownVal(cty.String), - `Required variable not set: The variable "constrained_string_required" is required, but is not set.`, - }, - { - "constrained_string_required", - cty.NullVal(cty.DynamicPseudoType), - cty.UnknownVal(cty.String), - `Required variable not set: Unsuitable value for var.constrained_string_required set from outside of the configuration: required variable may not be set to null.`, - }, - { - "constrained_string_required", - cty.StringVal("ahoy"), - cty.StringVal("ahoy"), - ``, - }, - { - "constrained_string_required", - cty.UnknownVal(cty.String), - cty.UnknownVal(cty.String), - ``, - }, - - // constrained_string_optional_default_string - { - "constrained_string_optional_default_string", - cty.NilVal, - cty.StringVal("hello"), // the declared default value - ``, - }, - { - "constrained_string_optional_default_string", - cty.NullVal(cty.DynamicPseudoType), - cty.StringVal("hello"), // the declared default value - ``, - }, - { - "constrained_string_optional_default_string", - cty.StringVal("ahoy"), - cty.StringVal("ahoy"), - ``, - }, - { - "constrained_string_optional_default_string", - cty.UnknownVal(cty.String), - cty.UnknownVal(cty.String), - ``, - }, - - // constrained_string_optional_default_bool - { - "constrained_string_optional_default_bool", - cty.NilVal, - cty.StringVal("true"), // the declared default value, automatically converted to match type constraint - ``, - }, - { - "constrained_string_optional_default_bool", - cty.NullVal(cty.DynamicPseudoType), - cty.StringVal("true"), // the declared default value, automatically converted to match type constraint - ``, - }, - { - "constrained_string_optional_default_bool", - cty.StringVal("ahoy"), - cty.StringVal("ahoy"), - ``, - }, - { - "constrained_string_optional_default_bool", - cty.UnknownVal(cty.String), - cty.UnknownVal(cty.String), - ``, - }, - { - "list_with_nested_collections_dynamic_with_default", - cty.TupleVal([]cty.Value{ - cty.ObjectVal(map[string]cty.Value{ - "name": cty.StringVal("default"), - }), - cty.ObjectVal(map[string]cty.Value{ - "name": cty.StringVal("complex"), - "taints": cty.ListVal([]cty.Value{ - cty.MapVal(map[string]cty.Value{ - "key": cty.StringVal("my_key"), - "value": cty.StringVal("my_value"), - }), - }), - }), - }), - cty.ListVal([]cty.Value{ - cty.ObjectVal(map[string]cty.Value{ - "name": cty.StringVal("default"), - "taints": cty.ListValEmpty(cty.Map(cty.String)), - }), - cty.ObjectVal(map[string]cty.Value{ - "name": cty.StringVal("complex"), - "taints": cty.ListVal([]cty.Value{ - cty.MapVal(map[string]cty.Value{ - "key": cty.StringVal("my_key"), - "value": cty.StringVal("my_value"), - }), - }), - }), - }), - ``, - }, - - // complex types - - { - "complex_type_with_nested_default_optional", - cty.SetVal([]cty.Value{ - cty.ObjectVal(map[string]cty.Value{ - "name": cty.StringVal("test1"), - "schedules": cty.SetVal([]cty.Value{ - cty.MapVal(map[string]cty.Value{ - "name": cty.StringVal("daily"), - }), - }), - }), - cty.ObjectVal(map[string]cty.Value{ - "name": cty.StringVal("test2"), - "schedules": cty.SetVal([]cty.Value{ - cty.MapVal(map[string]cty.Value{ - "name": cty.StringVal("daily"), - }), - cty.MapVal(map[string]cty.Value{ - "name": cty.StringVal("weekly"), - "cold_storage_after": cty.StringVal("0"), - }), - }), - }), - }), - cty.SetVal([]cty.Value{ - cty.ObjectVal(map[string]cty.Value{ - "name": cty.StringVal("test1"), - "schedules": cty.SetVal([]cty.Value{ - cty.ObjectVal(map[string]cty.Value{ - "name": cty.StringVal("daily"), - "cold_storage_after": cty.NumberIntVal(10), - }), - }), - }), - cty.ObjectVal(map[string]cty.Value{ - "name": cty.StringVal("test2"), - "schedules": cty.SetVal([]cty.Value{ - cty.ObjectVal(map[string]cty.Value{ - "name": cty.StringVal("daily"), - "cold_storage_after": cty.NumberIntVal(10), - }), - cty.ObjectVal(map[string]cty.Value{ - "name": cty.StringVal("weekly"), - "cold_storage_after": cty.NumberIntVal(0), - }), - }), - }), - }), - ``, - }, - { - "complex_type_with_nested_complex_types", - cty.ObjectVal(map[string]cty.Value{ - "name": cty.StringVal("object"), - "nested_object": cty.ObjectVal(map[string]cty.Value{ - "name": cty.StringVal("nested_object"), - }), - }), - cty.ObjectVal(map[string]cty.Value{ - "name": cty.StringVal("object"), - "nested_object": cty.ObjectVal(map[string]cty.Value{ - "name": cty.StringVal("nested_object"), - "value": cty.StringVal("foo"), - }), - "nested_object_with_default": cty.ObjectVal(map[string]cty.Value{ - "name": cty.StringVal("nested_object_with_default"), - "value": cty.StringVal("bar"), - }), - }), - ``, - }, - { - "complex_type_with_empty_default_and_nested_optional", - cty.ListVal([]cty.Value{ - cty.ObjectVal(map[string]cty.Value{ - "name": cty.StringVal("abc"), - "optional_list": cty.ListVal([]cty.Value{ - cty.ObjectVal(map[string]cty.Value{ - "string": cty.StringVal("child"), - "optional_string": cty.NullVal(cty.String), - }), - }), - }), - cty.ObjectVal(map[string]cty.Value{ - "name": cty.StringVal("def"), - "optional_list": cty.NullVal(cty.List(cty.Object(map[string]cty.Type{ - "string": cty.String, - "optional_string": cty.String, - }))), - }), - }), - cty.ListVal([]cty.Value{ - cty.ObjectVal(map[string]cty.Value{ - "name": cty.StringVal("abc"), - "optional_list": cty.ListVal([]cty.Value{ - cty.ObjectVal(map[string]cty.Value{ - "string": cty.StringVal("child"), - "optional_string": cty.NullVal(cty.String), - }), - }), - }), - cty.ObjectVal(map[string]cty.Value{ - "name": cty.StringVal("def"), - "optional_list": cty.ListValEmpty(cty.Object(map[string]cty.Type{ - "string": cty.String, - "optional_string": cty.String, - })), - }), - }), - ``, - }, - { - "object_with_nested_object_with_required_and_optional_attributes", - cty.EmptyObjectVal, - cty.ObjectVal(map[string]cty.Value{ - "nested_object": cty.NullVal(cty.Object(map[string]cty.Type{ - "string": cty.String, - "optional_string": cty.String, - })), - }), - ``, - }, - { - "empty_object_with_optional_nested_object_with_optional_bool", - cty.NilVal, - cty.ObjectVal(map[string]cty.Value{ - "thing": cty.NullVal(cty.Object(map[string]cty.Type{ - "flag": cty.Bool, - })), - }), - ``, - }, - { - "populated_object_with_optional_nested_object_with_optional_bool", - cty.NilVal, - cty.ObjectVal(map[string]cty.Value{ - "thing": cty.ObjectVal(map[string]cty.Value{ - "flag": cty.False, - }), - }), - ``, - }, - { - "empty_object_with_default_nested_object_with_optional_bool", - cty.NilVal, - cty.ObjectVal(map[string]cty.Value{ - "thing": cty.ObjectVal(map[string]cty.Value{ - "flag": cty.False, - }), - }), - ``, - }, - { - "list_with_nested_object_with_required_and_optional_attributes", - cty.ListVal([]cty.Value{ - cty.ObjectVal(map[string]cty.Value{ - "nested_object": cty.ObjectVal(map[string]cty.Value{ - "string": cty.StringVal("string"), - "optional_string": cty.NullVal(cty.String), - }), - }), - cty.ObjectVal(map[string]cty.Value{ - "nested_object": cty.NullVal(cty.Object(map[string]cty.Type{ - "string": cty.String, - "optional_string": cty.String, - })), - }), - }), - cty.ListVal([]cty.Value{ - cty.ObjectVal(map[string]cty.Value{ - "nested_object": cty.ObjectVal(map[string]cty.Value{ - "string": cty.StringVal("string"), - "optional_string": cty.StringVal("optional"), - }), - }), - cty.ObjectVal(map[string]cty.Value{ - "nested_object": cty.NullVal(cty.Object(map[string]cty.Type{ - "string": cty.String, - "optional_string": cty.String, - })), - }), - }), - ``, - }, - { - "list_with_nested_list_of_any", - cty.NilVal, - cty.ListVal([]cty.Value{ - cty.ObjectVal(map[string]cty.Value{ - "a": cty.StringVal("a"), - "b": cty.NullVal(cty.List(cty.Number)), - }), - cty.ObjectVal(map[string]cty.Value{ - "a": cty.StringVal("b"), - "b": cty.ListVal([]cty.Value{ - cty.NumberIntVal(1), - }), - }), - }), - ``, - }, - { - "list_with_nested_collections_dynamic_with_default", - cty.TupleVal([]cty.Value{ - cty.ObjectVal(map[string]cty.Value{ - "name": cty.StringVal("default"), - }), - cty.ObjectVal(map[string]cty.Value{ - "name": cty.StringVal("complex"), - "taints": cty.ListVal([]cty.Value{ - cty.MapVal(map[string]cty.Value{ - "key": cty.StringVal("my_key"), - "value": cty.StringVal("my_value"), - }), - }), - }), - }), - cty.ListVal([]cty.Value{ - cty.ObjectVal(map[string]cty.Value{ - "name": cty.StringVal("default"), - "taints": cty.ListValEmpty(cty.Map(cty.String)), - }), - cty.ObjectVal(map[string]cty.Value{ - "name": cty.StringVal("complex"), - "taints": cty.ListVal([]cty.Value{ - cty.MapVal(map[string]cty.Value{ - "key": cty.StringVal("my_key"), - "value": cty.StringVal("my_value"), - }), - }), - }), - }), - ``, - }, - { - "invalid_nested_type", - cty.MapVal(map[string]cty.Value{ - "mysql": cty.ObjectVal(map[string]cty.Value{ - "rules": cty.ObjectVal(map[string]cty.Value{ - "destination_addresses": cty.ListVal([]cty.Value{cty.StringVal("192.168.0.1")}), - }), - }), - }), - cty.UnknownVal(cty.Map(cty.Object(map[string]cty.Type{ - "rules": cty.Map(cty.Object(map[string]cty.Type{ - "destination_addresses": cty.List(cty.String), - })), - }))), - `Invalid value for input variable: Unsuitable value for var.invalid_nested_type set from outside of the configuration: incorrect map element type: attribute "rules": element "destination_addresses": object required.`, - }, - - // sensitive - { - "constrained_string_sensitive_required", - cty.UnknownVal(cty.String), - cty.UnknownVal(cty.String), - ``, - }, - } - - for _, test := range tests { - t.Run(fmt.Sprintf("%s %#v", test.varName, test.given), func(t *testing.T) { - varAddr := addrs.InputVariable{Name: test.varName}.Absolute(addrs.RootModuleInstance) - varCfg := variableConfigs[test.varName] - if varCfg == nil { - t.Fatalf("invalid variable name %q", test.varName) - } - - t.Logf( - "test case\nvariable: %s\nconstraint: %#v\ndefault: %#v\nnullable: %#v\ngiven value: %#v", - varAddr, - varCfg.Type, - varCfg.Default, - varCfg.Nullable, - test.given, - ) - - rawVal := &InputValue{ - Value: test.given, - SourceType: ValueFromCaller, - } - - got, diags := prepareFinalInputVariableValue( - varAddr, rawVal, varCfg, - ) - - if test.wantErr != "" { - if !diags.HasErrors() { - t.Errorf("unexpected success\nwant error: %s", test.wantErr) - } else if got, want := diags.Err().Error(), test.wantErr; got != want { - t.Errorf("wrong error\ngot: %s\nwant: %s", got, want) - } - } else { - if diags.HasErrors() { - t.Errorf("unexpected error\ngot: %s", diags.Err().Error()) - } - } - - // NOTE: should still have returned some reasonable value even if there was an error - if !test.want.RawEquals(got) { - t.Fatalf("wrong result\ngot: %#v\nwant: %#v", got, test.want) - } - }) - } - - t.Run("SourceType error message variants", func(t *testing.T) { - tests := []struct { - SourceType ValueSourceType - SourceRange tfdiags.SourceRange - WantTypeErr string - WantNullErr string - }{ - { - ValueFromUnknown, - tfdiags.SourceRange{}, - `Invalid value for input variable: Unsuitable value for var.constrained_string_required set from outside of the configuration: string required.`, - `Required variable not set: Unsuitable value for var.constrained_string_required set from outside of the configuration: required variable may not be set to null.`, - }, - { - ValueFromConfig, - tfdiags.SourceRange{ - Filename: "example.tf", - Start: tfdiags.SourcePos(hcl.InitialPos), - End: tfdiags.SourcePos(hcl.InitialPos), - }, - `Invalid value for input variable: The given value is not suitable for var.constrained_string_required declared at main.tf:32,3-41: string required.`, - `Required variable not set: The given value is not suitable for var.constrained_string_required defined at main.tf:32,3-41: required variable may not be set to null.`, - }, - { - ValueFromAutoFile, - tfdiags.SourceRange{ - Filename: "example.auto.tfvars", - Start: tfdiags.SourcePos(hcl.InitialPos), - End: tfdiags.SourcePos(hcl.InitialPos), - }, - `Invalid value for input variable: The given value is not suitable for var.constrained_string_required declared at main.tf:32,3-41: string required.`, - `Required variable not set: The given value is not suitable for var.constrained_string_required defined at main.tf:32,3-41: required variable may not be set to null.`, - }, - { - ValueFromNamedFile, - tfdiags.SourceRange{ - Filename: "example.tfvars", - Start: tfdiags.SourcePos(hcl.InitialPos), - End: tfdiags.SourcePos(hcl.InitialPos), - }, - `Invalid value for input variable: The given value is not suitable for var.constrained_string_required declared at main.tf:32,3-41: string required.`, - `Required variable not set: The given value is not suitable for var.constrained_string_required defined at main.tf:32,3-41: required variable may not be set to null.`, - }, - { - ValueFromCLIArg, - tfdiags.SourceRange{}, - `Invalid value for input variable: Unsuitable value for var.constrained_string_required set using -var="constrained_string_required=...": string required.`, - `Required variable not set: Unsuitable value for var.constrained_string_required set using -var="constrained_string_required=...": required variable may not be set to null.`, - }, - { - ValueFromEnvVar, - tfdiags.SourceRange{}, - `Invalid value for input variable: Unsuitable value for var.constrained_string_required set using the TF_VAR_constrained_string_required environment variable: string required.`, - `Required variable not set: Unsuitable value for var.constrained_string_required set using the TF_VAR_constrained_string_required environment variable: required variable may not be set to null.`, - }, - { - ValueFromInput, - tfdiags.SourceRange{}, - `Invalid value for input variable: Unsuitable value for var.constrained_string_required set using an interactive prompt: string required.`, - `Required variable not set: Unsuitable value for var.constrained_string_required set using an interactive prompt: required variable may not be set to null.`, - }, - { - // NOTE: This isn't actually a realistic case for this particular - // function, because if we have a value coming from a plan then - // we must be in the apply step, and we shouldn't be able to - // get past the plan step if we have invalid variable values, - // and during planning we'll always have other source types. - ValueFromPlan, - tfdiags.SourceRange{}, - `Invalid value for input variable: Unsuitable value for var.constrained_string_required set from outside of the configuration: string required.`, - `Required variable not set: Unsuitable value for var.constrained_string_required set from outside of the configuration: required variable may not be set to null.`, - }, - { - ValueFromCaller, - tfdiags.SourceRange{}, - `Invalid value for input variable: Unsuitable value for var.constrained_string_required set from outside of the configuration: string required.`, - `Required variable not set: Unsuitable value for var.constrained_string_required set from outside of the configuration: required variable may not be set to null.`, - }, - } - - for _, test := range tests { - t.Run(fmt.Sprintf("%s %s", test.SourceType, test.SourceRange.StartString()), func(t *testing.T) { - varAddr := addrs.InputVariable{Name: "constrained_string_required"}.Absolute(addrs.RootModuleInstance) - varCfg := variableConfigs[varAddr.Variable.Name] - t.Run("type error", func(t *testing.T) { - rawVal := &InputValue{ - Value: cty.EmptyObjectVal, - SourceType: test.SourceType, - SourceRange: test.SourceRange, - } - - _, diags := prepareFinalInputVariableValue( - varAddr, rawVal, varCfg, - ) - if !diags.HasErrors() { - t.Fatalf("unexpected success; want error") - } - - if got, want := diags.Err().Error(), test.WantTypeErr; got != want { - t.Errorf("wrong error\ngot: %s\nwant: %s", got, want) - } - }) - t.Run("null error", func(t *testing.T) { - rawVal := &InputValue{ - Value: cty.NullVal(cty.DynamicPseudoType), - SourceType: test.SourceType, - SourceRange: test.SourceRange, - } - - _, diags := prepareFinalInputVariableValue( - varAddr, rawVal, varCfg, - ) - if !diags.HasErrors() { - t.Fatalf("unexpected success; want error") - } - - if got, want := diags.Err().Error(), test.WantNullErr; got != want { - t.Errorf("wrong error\ngot: %s\nwant: %s", got, want) - } - }) - }) - } - }) - - t.Run("SensitiveVariable error message variants, with source variants", func(t *testing.T) { - tests := []struct { - SourceType ValueSourceType - SourceRange tfdiags.SourceRange - WantTypeErr string - HideSubject bool - }{ - { - ValueFromUnknown, - tfdiags.SourceRange{}, - "Invalid value for input variable: Unsuitable value for var.constrained_string_sensitive_required set from outside of the configuration: string required.", - false, - }, - { - ValueFromConfig, - tfdiags.SourceRange{ - Filename: "example.tfvars", - Start: tfdiags.SourcePos(hcl.InitialPos), - End: tfdiags.SourcePos(hcl.InitialPos), - }, - `Invalid value for input variable: The given value is not suitable for var.constrained_string_sensitive_required, which is sensitive: string required. Invalid value defined at example.tfvars:1,1-1.`, - true, - }, - } - - for _, test := range tests { - t.Run(fmt.Sprintf("%s %s", test.SourceType, test.SourceRange.StartString()), func(t *testing.T) { - varAddr := addrs.InputVariable{Name: "constrained_string_sensitive_required"}.Absolute(addrs.RootModuleInstance) - varCfg := variableConfigs[varAddr.Variable.Name] - t.Run("type error", func(t *testing.T) { - rawVal := &InputValue{ - Value: cty.EmptyObjectVal, - SourceType: test.SourceType, - SourceRange: test.SourceRange, - } - - _, diags := prepareFinalInputVariableValue( - varAddr, rawVal, varCfg, - ) - if !diags.HasErrors() { - t.Fatalf("unexpected success; want error") - } - - if got, want := diags.Err().Error(), test.WantTypeErr; got != want { - t.Errorf("wrong error\ngot: %s\nwant: %s", got, want) - } - - if test.HideSubject { - if got, want := diags[0].Source().Subject.StartString(), test.SourceRange.StartString(); got == want { - t.Errorf("Subject start should have been hidden, but was %s", got) - } - } - }) - }) - } - }) -} - -// These tests cover the JSON syntax configuration edge case handling, -// the background of which is described in detail in comments in the -// evalVariableValidations function. Future versions of Terraform may -// be able to remove this behaviour altogether. -func TestEvalVariableValidations_jsonErrorMessageEdgeCase(t *testing.T) { - cfgSrc := `{ - "variable": { - "valid": { - "type": "string", - "validation": { - "condition": "${var.valid != \"bar\"}", - "error_message": "Valid template string ${var.valid}" - } - }, - "invalid": { - "type": "string", - "validation": { - "condition": "${var.invalid != \"bar\"}", - "error_message": "Invalid template string ${" - } - } - } -} -` - cfg := testModuleInline(t, map[string]string{ - "main.tf.json": cfgSrc, - }) - variableConfigs := cfg.Module.Variables - - // Because we loaded our pseudo-module from a temporary file, the - // declaration source ranges will have unpredictable filenames. We'll - // fix that here just to make things easier below. - for _, vc := range variableConfigs { - vc.DeclRange.Filename = "main.tf.json" - for _, v := range vc.Validations { - v.DeclRange.Filename = "main.tf.json" - } - } - - tests := []struct { - varName string - given cty.Value - wantErr []string - wantWarn []string - }{ - // Valid variable validation declaration, assigned value which passes - // the condition generates no diagnostics. - { - varName: "valid", - given: cty.StringVal("foo"), - }, - // Assigning a value which fails the condition generates an error - // message with the expression successfully evaluated. - { - varName: "valid", - given: cty.StringVal("bar"), - wantErr: []string{ - "Invalid value for variable", - "Valid template string bar", - }, - }, - // Invalid variable validation declaration due to an unparseable - // template string. Assigning a value which passes the condition - // results in a warning about the error message. - { - varName: "invalid", - given: cty.StringVal("foo"), - wantWarn: []string{ - "Validation error message expression is invalid", - "Missing expression; Expected the start of an expression, but found the end of the file.", - }, - }, - // Assigning a value which fails the condition generates an error - // message including the configured string interpreted as a literal - // value, and the same warning diagnostic as above. - { - varName: "invalid", - given: cty.StringVal("bar"), - wantErr: []string{ - "Invalid value for variable", - "Invalid template string ${", - }, - wantWarn: []string{ - "Validation error message expression is invalid", - "Missing expression; Expected the start of an expression, but found the end of the file.", - }, - }, - } - - for _, test := range tests { - t.Run(fmt.Sprintf("%s %#v", test.varName, test.given), func(t *testing.T) { - varAddr := addrs.InputVariable{Name: test.varName}.Absolute(addrs.RootModuleInstance) - varCfg := variableConfigs[test.varName] - if varCfg == nil { - t.Fatalf("invalid variable name %q", test.varName) - } - - // Build a mock context to allow the function under test to - // retrieve the variable value and evaluate the expressions - ctx := &MockEvalContext{} - - // We need a minimal scope to allow basic functions to be passed to - // the HCL scope - ctx.EvaluationScopeScope = &lang.Scope{} - ctx.GetVariableValueFunc = func(addr addrs.AbsInputVariableInstance) cty.Value { - if got, want := addr.String(), varAddr.String(); got != want { - t.Errorf("incorrect argument to GetVariableValue: got %s, want %s", got, want) - } - return test.given - } - - gotDiags := evalVariableValidations( - varAddr, varCfg, nil, ctx, - ) - - if len(test.wantErr) == 0 && len(test.wantWarn) == 0 { - if len(gotDiags) > 0 { - t.Errorf("no diags expected, got %s", gotDiags.Err().Error()) - } - } else { - wantErrs: - for _, want := range test.wantErr { - for _, diag := range gotDiags { - if diag.Severity() != tfdiags.Error { - continue - } - desc := diag.Description() - if strings.Contains(desc.Summary, want) || strings.Contains(desc.Detail, want) { - continue wantErrs - } - } - t.Errorf("no error diagnostics found containing %q\ngot: %s", want, gotDiags.Err().Error()) - } - - wantWarns: - for _, want := range test.wantWarn { - for _, diag := range gotDiags { - if diag.Severity() != tfdiags.Warning { - continue - } - desc := diag.Description() - if strings.Contains(desc.Summary, want) || strings.Contains(desc.Detail, want) { - continue wantWarns - } - } - t.Errorf("no warning diagnostics found containing %q\ngot: %s", want, gotDiags.Err().Error()) - } - } - }) - } -} - -func TestEvalVariableValidations_sensitiveValues(t *testing.T) { - cfgSrc := ` -variable "foo" { - type = string - sensitive = true - default = "boop" - - validation { - condition = length(var.foo) == 4 - error_message = "Foo must be 4 characters, not ${length(var.foo)}" - } -} - -variable "bar" { - type = string - sensitive = true - default = "boop" - - validation { - condition = length(var.bar) == 4 - error_message = "Bar must be 4 characters, not ${nonsensitive(length(var.bar))}." - } -} -` - cfg := testModuleInline(t, map[string]string{ - "main.tf": cfgSrc, - }) - variableConfigs := cfg.Module.Variables - - // Because we loaded our pseudo-module from a temporary file, the - // declaration source ranges will have unpredictable filenames. We'll - // fix that here just to make things easier below. - for _, vc := range variableConfigs { - vc.DeclRange.Filename = "main.tf" - for _, v := range vc.Validations { - v.DeclRange.Filename = "main.tf" - } - } - - tests := []struct { - varName string - given cty.Value - wantErr []string - }{ - // Validations pass on a sensitive variable with an error message which - // would generate a sensitive value - { - varName: "foo", - given: cty.StringVal("boop"), - }, - // Assigning a value which fails the condition generates a sensitive - // error message, which is elided and generates another error - { - varName: "foo", - given: cty.StringVal("bap"), - wantErr: []string{ - "Invalid value for variable", - "The error message included a sensitive value, so it will not be displayed.", - "Error message refers to sensitive values", - }, - }, - // Validations pass on a sensitive variable with a correctly defined - // error message - { - varName: "bar", - given: cty.StringVal("boop"), - }, - // Assigning a value which fails the condition generates a nonsensitive - // error message, which is displayed - { - varName: "bar", - given: cty.StringVal("bap"), - wantErr: []string{ - "Invalid value for variable", - "Bar must be 4 characters, not 3.", - }, - }, - } - - for _, test := range tests { - t.Run(fmt.Sprintf("%s %#v", test.varName, test.given), func(t *testing.T) { - varAddr := addrs.InputVariable{Name: test.varName}.Absolute(addrs.RootModuleInstance) - varCfg := variableConfigs[test.varName] - if varCfg == nil { - t.Fatalf("invalid variable name %q", test.varName) - } - - // Build a mock context to allow the function under test to - // retrieve the variable value and evaluate the expressions - ctx := &MockEvalContext{} - - // We need a minimal scope to allow basic functions to be passed to - // the HCL scope - ctx.EvaluationScopeScope = &lang.Scope{} - ctx.GetVariableValueFunc = func(addr addrs.AbsInputVariableInstance) cty.Value { - if got, want := addr.String(), varAddr.String(); got != want { - t.Errorf("incorrect argument to GetVariableValue: got %s, want %s", got, want) - } - if varCfg.Sensitive { - return test.given.Mark(marks.Sensitive) - } else { - return test.given - } - } - - gotDiags := evalVariableValidations( - varAddr, varCfg, nil, ctx, - ) - - if len(test.wantErr) == 0 { - if len(gotDiags) > 0 { - t.Errorf("no diags expected, got %s", gotDiags.Err().Error()) - } - } else { - wantErrs: - for _, want := range test.wantErr { - for _, diag := range gotDiags { - if diag.Severity() != tfdiags.Error { - continue - } - desc := diag.Description() - if strings.Contains(desc.Summary, want) || strings.Contains(desc.Detail, want) { - continue wantErrs - } - } - t.Errorf("no error diagnostics found containing %q\ngot: %s", want, gotDiags.Err().Error()) - } - } - }) - } -} diff --git a/internal/terraform/evaluate.go b/internal/terraform/evaluate.go deleted file mode 100644 index d680136d8dcd..000000000000 --- a/internal/terraform/evaluate.go +++ /dev/null @@ -1,966 +0,0 @@ -package terraform - -import ( - "fmt" - "log" - "os" - "path/filepath" - "sync" - - "github.com/agext/levenshtein" - "github.com/hashicorp/hcl/v2" - "github.com/zclconf/go-cty/cty" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/instances" - "github.com/hashicorp/terraform/internal/lang" - "github.com/hashicorp/terraform/internal/lang/marks" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -// Evaluator provides the necessary contextual data for evaluating expressions -// for a particular walk operation. -type Evaluator struct { - // Operation defines what type of operation this evaluator is being used - // for. - Operation walkOperation - - // Meta is contextual metadata about the current operation. - Meta *ContextMeta - - // Config is the root node in the configuration tree. - Config *configs.Config - - // VariableValues is a map from variable names to their associated values, - // within the module indicated by ModulePath. VariableValues is modified - // concurrently, and so it must be accessed only while holding - // VariableValuesLock. - // - // The first map level is string representations of addr.ModuleInstance - // values, while the second level is variable names. - VariableValues map[string]map[string]cty.Value - VariableValuesLock *sync.Mutex - - // Plugins is the library of available plugin components (providers and - // provisioners) that we have available to help us evaluate expressions - // that interact with plugin-provided objects. - // - // From this we only access the schemas of the plugins, and don't otherwise - // interact with plugin instances. - Plugins *contextPlugins - - // State is the current state, embedded in a wrapper that ensures that - // it can be safely accessed and modified concurrently. - State *states.SyncState - - // Changes is the set of proposed changes, embedded in a wrapper that - // ensures they can be safely accessed and modified concurrently. - Changes *plans.ChangesSync -} - -// Scope creates an evaluation scope for the given module path and optional -// resource. -// -// If the "self" argument is nil then the "self" object is not available -// in evaluated expressions. Otherwise, it behaves as an alias for the given -// address. -func (e *Evaluator) Scope(data lang.Data, self addrs.Referenceable) *lang.Scope { - return &lang.Scope{ - Data: data, - SelfAddr: self, - PureOnly: e.Operation != walkApply && e.Operation != walkDestroy && e.Operation != walkEval, - BaseDir: ".", // Always current working directory for now. - } -} - -// evaluationStateData is an implementation of lang.Data that resolves -// references primarily (but not exclusively) using information from a State. -type evaluationStateData struct { - Evaluator *Evaluator - - // ModulePath is the path through the dynamic module tree to the module - // that references will be resolved relative to. - ModulePath addrs.ModuleInstance - - // InstanceKeyData describes the values, if any, that are accessible due - // to repetition of a containing object using "count" or "for_each" - // arguments. (It is _not_ used for the for_each inside "dynamic" blocks, - // since the user specifies in that case which variable name to locally - // shadow.) - InstanceKeyData InstanceKeyEvalData - - // Operation records the type of walk the evaluationStateData is being used - // for. - Operation walkOperation -} - -// InstanceKeyEvalData is the old name for instances.RepetitionData, aliased -// here for compatibility. In new code, use instances.RepetitionData instead. -type InstanceKeyEvalData = instances.RepetitionData - -// EvalDataForInstanceKey constructs a suitable InstanceKeyEvalData for -// evaluating in a context that has the given instance key. -// -// The forEachMap argument can be nil when preparing for evaluation -// in a context where each.value is prohibited, such as a destroy-time -// provisioner. In that case, the returned EachValue will always be -// cty.NilVal. -func EvalDataForInstanceKey(key addrs.InstanceKey, forEachMap map[string]cty.Value) InstanceKeyEvalData { - var evalData InstanceKeyEvalData - if key == nil { - return evalData - } - - keyValue := key.Value() - switch keyValue.Type() { - case cty.String: - evalData.EachKey = keyValue - evalData.EachValue = forEachMap[keyValue.AsString()] - case cty.Number: - evalData.CountIndex = keyValue - } - return evalData -} - -// EvalDataForNoInstanceKey is a value of InstanceKeyData that sets no instance -// key values at all, suitable for use in contexts where no keyed instance -// is relevant. -var EvalDataForNoInstanceKey = InstanceKeyEvalData{} - -// evaluationStateData must implement lang.Data -var _ lang.Data = (*evaluationStateData)(nil) - -func (d *evaluationStateData) GetCountAttr(addr addrs.CountAttr, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - switch addr.Name { - - case "index": - idxVal := d.InstanceKeyData.CountIndex - if idxVal == cty.NilVal { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: `Reference to "count" in non-counted context`, - Detail: `The "count" object can only be used in "module", "resource", and "data" blocks, and only when the "count" argument is set.`, - Subject: rng.ToHCL().Ptr(), - }) - return cty.UnknownVal(cty.Number), diags - } - return idxVal, diags - - default: - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: `Invalid "count" attribute`, - Detail: fmt.Sprintf(`The "count" object does not have an attribute named %q. The only supported attribute is count.index, which is the index of each instance of a resource block that has the "count" argument set.`, addr.Name), - Subject: rng.ToHCL().Ptr(), - }) - return cty.DynamicVal, diags - } -} - -func (d *evaluationStateData) GetForEachAttr(addr addrs.ForEachAttr, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - var returnVal cty.Value - switch addr.Name { - - case "key": - returnVal = d.InstanceKeyData.EachKey - case "value": - returnVal = d.InstanceKeyData.EachValue - - if returnVal == cty.NilVal { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: `each.value cannot be used in this context`, - Detail: `A reference to "each.value" has been used in a context in which it is unavailable, such as when the configuration no longer contains the value in its "for_each" expression. Remove this reference to each.value in your configuration to work around this error.`, - Subject: rng.ToHCL().Ptr(), - }) - return cty.UnknownVal(cty.DynamicPseudoType), diags - } - default: - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: `Invalid "each" attribute`, - Detail: fmt.Sprintf(`The "each" object does not have an attribute named %q. The supported attributes are each.key and each.value, the current key and value pair of the "for_each" attribute set.`, addr.Name), - Subject: rng.ToHCL().Ptr(), - }) - return cty.DynamicVal, diags - } - - if returnVal == cty.NilVal { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: `Reference to "each" in context without for_each`, - Detail: `The "each" object can be used only in "module" or "resource" blocks, and only when the "for_each" argument is set.`, - Subject: rng.ToHCL().Ptr(), - }) - return cty.UnknownVal(cty.DynamicPseudoType), diags - } - return returnVal, diags -} - -func (d *evaluationStateData) GetInputVariable(addr addrs.InputVariable, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - - // First we'll make sure the requested value is declared in configuration, - // so we can produce a nice message if not. - moduleConfig := d.Evaluator.Config.DescendentForInstance(d.ModulePath) - if moduleConfig == nil { - // should never happen, since we can't be evaluating in a module - // that wasn't mentioned in configuration. - panic(fmt.Sprintf("input variable read from %s, which has no configuration", d.ModulePath)) - } - - config := moduleConfig.Module.Variables[addr.Name] - if config == nil { - var suggestions []string - for k := range moduleConfig.Module.Variables { - suggestions = append(suggestions, k) - } - suggestion := nameSuggestion(addr.Name, suggestions) - if suggestion != "" { - suggestion = fmt.Sprintf(" Did you mean %q?", suggestion) - } else { - suggestion = fmt.Sprintf(" This variable can be declared with a variable %q {} block.", addr.Name) - } - - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: `Reference to undeclared input variable`, - Detail: fmt.Sprintf(`An input variable with the name %q has not been declared.%s`, addr.Name, suggestion), - Subject: rng.ToHCL().Ptr(), - }) - return cty.DynamicVal, diags - } - d.Evaluator.VariableValuesLock.Lock() - defer d.Evaluator.VariableValuesLock.Unlock() - - // During the validate walk, input variables are always unknown so - // that we are validating the configuration for all possible input values - // rather than for a specific set. Checking against a specific set of - // input values then happens during the plan walk. - // - // This is important because otherwise the validation walk will tend to be - // overly strict, requiring expressions throughout the configuration to - // be complicated to accommodate all possible inputs, whereas returning - // unknown here allows for simpler patterns like using input values as - // guards to broadly enable/disable resources, avoid processing things - // that are disabled, etc. Terraform's static validation leans towards - // being liberal in what it accepts because the subsequent plan walk has - // more information available and so can be more conservative. - if d.Operation == walkValidate { - // Ensure variable sensitivity is captured in the validate walk - if config.Sensitive { - return cty.UnknownVal(config.Type).Mark(marks.Sensitive), diags - } - return cty.UnknownVal(config.Type), diags - } - - moduleAddrStr := d.ModulePath.String() - vals := d.Evaluator.VariableValues[moduleAddrStr] - if vals == nil { - return cty.UnknownVal(config.Type), diags - } - - // d.Evaluator.VariableValues should always contain valid "final values" - // for variables, which is to say that they have already had type - // conversions, validations, and default value handling applied to them. - // Those are the responsibility of the graph notes representing the - // variable declarations. Therefore here we just trust that we already - // have a correct value. - - val, isSet := vals[addr.Name] - if !isSet { - // We should not be able to get here without having a valid value - // for every variable, so this always indicates a bug in either - // the graph builder (not including all the needed nodes) or in - // the graph nodes representing variables. - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: `Reference to unresolved input variable`, - Detail: fmt.Sprintf( - `The final value for %s is missing in Terraform's evaluation context. This is a bug in Terraform; please report it!`, - addr.Absolute(d.ModulePath), - ), - Subject: rng.ToHCL().Ptr(), - }) - val = cty.UnknownVal(config.Type) - } - - // Mark if sensitive - if config.Sensitive { - val = val.Mark(marks.Sensitive) - } - - return val, diags -} - -func (d *evaluationStateData) GetLocalValue(addr addrs.LocalValue, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - - // First we'll make sure the requested value is declared in configuration, - // so we can produce a nice message if not. - moduleConfig := d.Evaluator.Config.DescendentForInstance(d.ModulePath) - if moduleConfig == nil { - // should never happen, since we can't be evaluating in a module - // that wasn't mentioned in configuration. - panic(fmt.Sprintf("local value read from %s, which has no configuration", d.ModulePath)) - } - - config := moduleConfig.Module.Locals[addr.Name] - if config == nil { - var suggestions []string - for k := range moduleConfig.Module.Locals { - suggestions = append(suggestions, k) - } - suggestion := nameSuggestion(addr.Name, suggestions) - if suggestion != "" { - suggestion = fmt.Sprintf(" Did you mean %q?", suggestion) - } - - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: `Reference to undeclared local value`, - Detail: fmt.Sprintf(`A local value with the name %q has not been declared.%s`, addr.Name, suggestion), - Subject: rng.ToHCL().Ptr(), - }) - return cty.DynamicVal, diags - } - - val := d.Evaluator.State.LocalValue(addr.Absolute(d.ModulePath)) - if val == cty.NilVal { - // Not evaluated yet? - val = cty.DynamicVal - } - - return val, diags -} - -func (d *evaluationStateData) GetModule(addr addrs.ModuleCall, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - - // Output results live in the module that declares them, which is one of - // the child module instances of our current module path. - moduleAddr := d.ModulePath.Module().Child(addr.Name) - - parentCfg := d.Evaluator.Config.DescendentForInstance(d.ModulePath) - callConfig, ok := parentCfg.Module.ModuleCalls[addr.Name] - if !ok { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: `Reference to undeclared module`, - Detail: fmt.Sprintf(`The configuration contains no %s.`, moduleAddr), - Subject: rng.ToHCL().Ptr(), - }) - return cty.DynamicVal, diags - } - - // We'll consult the configuration to see what output names we are - // expecting, so we can ensure the resulting object is of the expected - // type even if our data is incomplete for some reason. - moduleConfig := d.Evaluator.Config.Descendent(moduleAddr) - if moduleConfig == nil { - // should never happen, since we have a valid module call above, this - // should be caught during static validation. - panic(fmt.Sprintf("output value read from %s, which has no configuration", moduleAddr)) - } - outputConfigs := moduleConfig.Module.Outputs - - // Collect all the relevant outputs that current exist in the state. - // We know the instance path up to this point, and the child module name, - // so we only need to store these by instance key. - stateMap := map[addrs.InstanceKey]map[string]cty.Value{} - for _, output := range d.Evaluator.State.ModuleOutputs(d.ModulePath, addr) { - val := output.Value - if output.Sensitive { - val = val.Mark(marks.Sensitive) - } - - _, callInstance := output.Addr.Module.CallInstance() - instance, ok := stateMap[callInstance.Key] - if !ok { - instance = map[string]cty.Value{} - stateMap[callInstance.Key] = instance - } - - instance[output.Addr.OutputValue.Name] = val - } - - // Get all changes that reside for this module call within our path. - // The change contains the full addr, so we can key these with strings. - changesMap := map[addrs.InstanceKey]map[string]*plans.OutputChangeSrc{} - for _, change := range d.Evaluator.Changes.GetOutputChanges(d.ModulePath, addr) { - _, callInstance := change.Addr.Module.CallInstance() - instance, ok := changesMap[callInstance.Key] - if !ok { - instance = map[string]*plans.OutputChangeSrc{} - changesMap[callInstance.Key] = instance - } - - instance[change.Addr.OutputValue.Name] = change - } - - // Build up all the module objects, creating a map of values for each - // module instance. - moduleInstances := map[addrs.InstanceKey]map[string]cty.Value{} - - // create a dummy object type for validation below - unknownMap := map[string]cty.Type{} - - // the structure is based on the configuration, so iterate through all the - // defined outputs, and add any instance state or changes we find. - for _, cfg := range outputConfigs { - // record the output names for validation - unknownMap[cfg.Name] = cty.DynamicPseudoType - - // get all instance output for this path from the state - for key, states := range stateMap { - outputState, ok := states[cfg.Name] - if !ok { - continue - } - - instance, ok := moduleInstances[key] - if !ok { - instance = map[string]cty.Value{} - moduleInstances[key] = instance - } - - instance[cfg.Name] = outputState - } - - // any pending changes override the state state values - for key, changes := range changesMap { - changeSrc, ok := changes[cfg.Name] - if !ok { - continue - } - - instance, ok := moduleInstances[key] - if !ok { - instance = map[string]cty.Value{} - moduleInstances[key] = instance - } - - change, err := changeSrc.Decode() - if err != nil { - // This should happen only if someone has tampered with a plan - // file, so we won't bother with a pretty error for it. - diags = diags.Append(fmt.Errorf("planned change for %s could not be decoded: %s", addr, err)) - instance[cfg.Name] = cty.DynamicVal - continue - } - - instance[cfg.Name] = change.After - - if change.Sensitive { - instance[cfg.Name] = change.After.Mark(marks.Sensitive) - } - } - } - - var ret cty.Value - - // compile the outputs into the correct value type for the each mode - switch { - case callConfig.Count != nil: - // figure out what the last index we have is - length := -1 - for key := range moduleInstances { - intKey, ok := key.(addrs.IntKey) - if !ok { - // old key from state which is being dropped - continue - } - if int(intKey) >= length { - length = int(intKey) + 1 - } - } - - if length > 0 { - vals := make([]cty.Value, length) - for key, instance := range moduleInstances { - intKey, ok := key.(addrs.IntKey) - if !ok { - // old key from state which is being dropped - continue - } - - vals[int(intKey)] = cty.ObjectVal(instance) - } - - // Insert unknown values where there are any missing instances - for i, v := range vals { - if v.IsNull() { - vals[i] = cty.DynamicVal - continue - } - } - ret = cty.TupleVal(vals) - } else { - ret = cty.EmptyTupleVal - } - - case callConfig.ForEach != nil: - vals := make(map[string]cty.Value) - for key, instance := range moduleInstances { - strKey, ok := key.(addrs.StringKey) - if !ok { - continue - } - - vals[string(strKey)] = cty.ObjectVal(instance) - } - - if len(vals) > 0 { - ret = cty.ObjectVal(vals) - } else { - ret = cty.EmptyObjectVal - } - - default: - val, ok := moduleInstances[addrs.NoKey] - if !ok { - // create the object if there wasn't one known - val = map[string]cty.Value{} - for k := range outputConfigs { - val[k] = cty.DynamicVal - } - } - - ret = cty.ObjectVal(val) - } - - // The module won't be expanded during validation, so we need to return an - // unknown value. This will ensure the types looks correct, since we built - // the objects based on the configuration. - if d.Operation == walkValidate { - // While we know the type here and it would be nice to validate whether - // indexes are valid or not, because tuples and objects have fixed - // numbers of elements we can't simply return an unknown value of the - // same type since we have not expanded any instances during - // validation. - // - // In order to validate the expression a little precisely, we'll create - // an unknown map or list here to get more type information. - ty := cty.Object(unknownMap) - switch { - case callConfig.Count != nil: - ret = cty.UnknownVal(cty.List(ty)) - case callConfig.ForEach != nil: - ret = cty.UnknownVal(cty.Map(ty)) - default: - ret = cty.UnknownVal(ty) - } - } - - return ret, diags -} - -func (d *evaluationStateData) GetPathAttr(addr addrs.PathAttr, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - switch addr.Name { - - case "cwd": - var err error - var wd string - if d.Evaluator.Meta != nil { - // Meta is always non-nil in the normal case, but some test cases - // are not so realistic. - wd = d.Evaluator.Meta.OriginalWorkingDir - } - if wd == "" { - wd, err = os.Getwd() - if err != nil { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: `Failed to get working directory`, - Detail: fmt.Sprintf(`The value for path.cwd cannot be determined due to a system error: %s`, err), - Subject: rng.ToHCL().Ptr(), - }) - return cty.DynamicVal, diags - } - } - // The current working directory should always be absolute, whether we - // just looked it up or whether we were relying on ContextMeta's - // (possibly non-normalized) path. - wd, err = filepath.Abs(wd) - if err != nil { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: `Failed to get working directory`, - Detail: fmt.Sprintf(`The value for path.cwd cannot be determined due to a system error: %s`, err), - Subject: rng.ToHCL().Ptr(), - }) - return cty.DynamicVal, diags - } - - return cty.StringVal(filepath.ToSlash(wd)), diags - - case "module": - moduleConfig := d.Evaluator.Config.DescendentForInstance(d.ModulePath) - if moduleConfig == nil { - // should never happen, since we can't be evaluating in a module - // that wasn't mentioned in configuration. - panic(fmt.Sprintf("module.path read from module %s, which has no configuration", d.ModulePath)) - } - sourceDir := moduleConfig.Module.SourceDir - return cty.StringVal(filepath.ToSlash(sourceDir)), diags - - case "root": - sourceDir := d.Evaluator.Config.Module.SourceDir - return cty.StringVal(filepath.ToSlash(sourceDir)), diags - - default: - suggestion := nameSuggestion(addr.Name, []string{"cwd", "module", "root"}) - if suggestion != "" { - suggestion = fmt.Sprintf(" Did you mean %q?", suggestion) - } - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: `Invalid "path" attribute`, - Detail: fmt.Sprintf(`The "path" object does not have an attribute named %q.%s`, addr.Name, suggestion), - Subject: rng.ToHCL().Ptr(), - }) - return cty.DynamicVal, diags - } -} - -func (d *evaluationStateData) GetResource(addr addrs.Resource, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - // First we'll consult the configuration to see if an resource of this - // name is declared at all. - moduleAddr := d.ModulePath - moduleConfig := d.Evaluator.Config.DescendentForInstance(moduleAddr) - if moduleConfig == nil { - // should never happen, since we can't be evaluating in a module - // that wasn't mentioned in configuration. - panic(fmt.Sprintf("resource value read from %s, which has no configuration", moduleAddr)) - } - - config := moduleConfig.Module.ResourceByAddr(addr) - if config == nil { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: `Reference to undeclared resource`, - Detail: fmt.Sprintf(`A resource %q %q has not been declared in %s`, addr.Type, addr.Name, moduleDisplayAddr(moduleAddr)), - Subject: rng.ToHCL().Ptr(), - }) - return cty.DynamicVal, diags - } - - // Build the provider address from configuration, since we may not have - // state available in all cases. - // We need to build an abs provider address, but we can use a default - // instance since we're only interested in the schema. - schema := d.getResourceSchema(addr, config.Provider) - if schema == nil { - // This shouldn't happen, since validation before we get here should've - // taken care of it, but we'll show a reasonable error message anyway. - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: `Missing resource type schema`, - Detail: fmt.Sprintf("No schema is available for %s in %s. This is a bug in Terraform and should be reported.", addr, config.Provider), - Subject: rng.ToHCL().Ptr(), - }) - return cty.DynamicVal, diags - } - ty := schema.ImpliedType() - - rs := d.Evaluator.State.Resource(addr.Absolute(d.ModulePath)) - - if rs == nil { - switch d.Operation { - case walkPlan, walkApply: - // During plan and apply as we evaluate each removed instance they - // are removed from the working state. Since we know there are no - // instances, return an empty container of the expected type. - switch { - case config.Count != nil: - return cty.EmptyTupleVal, diags - case config.ForEach != nil: - return cty.EmptyObjectVal, diags - default: - // While we can reference an expanded resource with 0 - // instances, we cannot reference instances that do not exist. - // Due to the fact that we may have direct references to - // instances that may end up in a root output during destroy - // (since a planned destroy cannot yet remove root outputs), we - // need to return a dynamic value here to allow evaluation to - // continue. - log.Printf("[ERROR] unknown instance %q referenced during %s", addr.Absolute(d.ModulePath), d.Operation) - return cty.DynamicVal, diags - } - - case walkImport: - // Import does not yet plan resource changes, so new resources from - // config are not going to be found here. Once walkImport fully - // plans resources, this case should not longer be needed. - // In the single instance case, we can return a typed unknown value - // for the instance to better satisfy other expressions using the - // value. This of course will not help if statically known - // attributes are expected to be known elsewhere, but reduces the - // number of problematic configs for now. - // Unlike in plan and apply above we can't be sure the count or - // for_each instances are empty, so we return a DynamicVal. We - // don't really have a good value to return otherwise -- empty - // values will fail for direct index expressions, and unknown - // Lists and Maps could fail in some type unifications. - switch { - case config.Count != nil: - return cty.DynamicVal, diags - case config.ForEach != nil: - return cty.DynamicVal, diags - default: - return cty.UnknownVal(ty), diags - } - - default: - // We should only end up here during the validate walk, - // since later walks should have at least partial states populated - // for all resources in the configuration. - return cty.DynamicVal, diags - } - } - - // Decode all instances in the current state - instances := map[addrs.InstanceKey]cty.Value{} - pendingDestroy := d.Operation == walkDestroy - for key, is := range rs.Instances { - if is == nil || is.Current == nil { - // Assume we're dealing with an instance that hasn't been created yet. - instances[key] = cty.UnknownVal(ty) - continue - } - - instAddr := addr.Instance(key).Absolute(d.ModulePath) - - change := d.Evaluator.Changes.GetResourceInstanceChange(instAddr, states.CurrentGen) - if change != nil { - // Don't take any resources that are yet to be deleted into account. - // If the referenced resource is CreateBeforeDestroy, then orphaned - // instances will be in the state, as they are not destroyed until - // after their dependants are updated. - if change.Action == plans.Delete { - if !pendingDestroy { - continue - } - } - } - - // Planned resources are temporarily stored in state with empty values, - // and need to be replaced by the planned value here. - if is.Current.Status == states.ObjectPlanned { - if change == nil { - // If the object is in planned status then we should not get - // here, since we should have found a pending value in the plan - // above instead. - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Missing pending object in plan", - Detail: fmt.Sprintf("Instance %s is marked as having a change pending but that change is not recorded in the plan. This is a bug in Terraform; please report it.", instAddr), - Subject: &config.DeclRange, - }) - continue - } - val, err := change.After.Decode(ty) - if err != nil { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid resource instance data in plan", - Detail: fmt.Sprintf("Instance %s data could not be decoded from the plan: %s.", instAddr, err), - Subject: &config.DeclRange, - }) - continue - } - - // If our provider schema contains sensitive values, mark those as sensitive - afterMarks := change.AfterValMarks - if schema.ContainsSensitive() { - afterMarks = append(afterMarks, schema.ValueMarks(val, nil)...) - } - - instances[key] = val.MarkWithPaths(afterMarks) - continue - } - - ios, err := is.Current.Decode(ty) - if err != nil { - // This shouldn't happen, since by the time we get here we - // should have upgraded the state data already. - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid resource instance data in state", - Detail: fmt.Sprintf("Instance %s data could not be decoded from the state: %s.", instAddr, err), - Subject: &config.DeclRange, - }) - continue - } - - val := ios.Value - - // If our schema contains sensitive values, mark those as sensitive. - // Since decoding the instance object can also apply sensitivity marks, - // we must remove and combine those before remarking to avoid a double- - // mark error. - if schema.ContainsSensitive() { - var marks []cty.PathValueMarks - val, marks = val.UnmarkDeepWithPaths() - marks = append(marks, schema.ValueMarks(val, nil)...) - val = val.MarkWithPaths(marks) - } - instances[key] = val - } - - // ret should be populated with a valid value in all cases below - var ret cty.Value - - switch { - case config.Count != nil: - // figure out what the last index we have is - length := -1 - for key := range instances { - intKey, ok := key.(addrs.IntKey) - if !ok { - continue - } - if int(intKey) >= length { - length = int(intKey) + 1 - } - } - - if length > 0 { - vals := make([]cty.Value, length) - for key, instance := range instances { - intKey, ok := key.(addrs.IntKey) - if !ok { - // old key from state, which isn't valid for evaluation - continue - } - - vals[int(intKey)] = instance - } - - // Insert unknown values where there are any missing instances - for i, v := range vals { - if v == cty.NilVal { - vals[i] = cty.UnknownVal(ty) - } - } - ret = cty.TupleVal(vals) - } else { - ret = cty.EmptyTupleVal - } - - case config.ForEach != nil: - vals := make(map[string]cty.Value) - for key, instance := range instances { - strKey, ok := key.(addrs.StringKey) - if !ok { - // old key that is being dropped and not used for evaluation - continue - } - vals[string(strKey)] = instance - } - - if len(vals) > 0 { - // We use an object rather than a map here because resource schemas - // may include dynamically-typed attributes, which will then cause - // each instance to potentially have a different runtime type even - // though they all conform to the static schema. - ret = cty.ObjectVal(vals) - } else { - ret = cty.EmptyObjectVal - } - - default: - val, ok := instances[addrs.NoKey] - if !ok { - // if the instance is missing, insert an unknown value - val = cty.UnknownVal(ty) - } - - ret = val - } - - return ret, diags -} - -func (d *evaluationStateData) getResourceSchema(addr addrs.Resource, providerAddr addrs.Provider) *configschema.Block { - schema, _, err := d.Evaluator.Plugins.ResourceTypeSchema(providerAddr, addr.Mode, addr.Type) - if err != nil { - // We have plently other codepaths that will detect and report - // schema lookup errors before we'd reach this point, so we'll just - // treat a failure here the same as having no schema. - return nil - } - return schema -} - -func (d *evaluationStateData) GetTerraformAttr(addr addrs.TerraformAttr, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - switch addr.Name { - - case "workspace": - workspaceName := d.Evaluator.Meta.Env - return cty.StringVal(workspaceName), diags - - case "env": - // Prior to Terraform 0.12 there was an attribute "env", which was - // an alias name for "workspace". This was deprecated and is now - // removed. - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: `Invalid "terraform" attribute`, - Detail: `The terraform.env attribute was deprecated in v0.10 and removed in v0.12. The "state environment" concept was renamed to "workspace" in v0.12, and so the workspace name can now be accessed using the terraform.workspace attribute.`, - Subject: rng.ToHCL().Ptr(), - }) - return cty.DynamicVal, diags - - default: - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: `Invalid "terraform" attribute`, - Detail: fmt.Sprintf(`The "terraform" object does not have an attribute named %q. The only supported attribute is terraform.workspace, the name of the currently-selected workspace.`, addr.Name), - Subject: rng.ToHCL().Ptr(), - }) - return cty.DynamicVal, diags - } -} - -// nameSuggestion tries to find a name from the given slice of suggested names -// that is close to the given name and returns it if found. If no suggestion -// is close enough, returns the empty string. -// -// The suggestions are tried in order, so earlier suggestions take precedence -// if the given string is similar to two or more suggestions. -// -// This function is intended to be used with a relatively-small number of -// suggestions. It's not optimized for hundreds or thousands of them. -func nameSuggestion(given string, suggestions []string) string { - for _, suggestion := range suggestions { - dist := levenshtein.Distance(given, suggestion, nil) - if dist < 3 { // threshold determined experimentally - return suggestion - } - } - return "" -} - -// moduleDisplayAddr returns a string describing the given module instance -// address that is appropriate for returning to users in situations where the -// root module is possible. Specifically, it returns "the root module" if the -// root module instance is given, or a string representation of the module -// address otherwise. -func moduleDisplayAddr(addr addrs.ModuleInstance) string { - switch { - case addr.IsRoot(): - return "the root module" - default: - return addr.String() - } -} diff --git a/internal/terraform/evaluate_test.go b/internal/terraform/evaluate_test.go deleted file mode 100644 index 765efded6859..000000000000 --- a/internal/terraform/evaluate_test.go +++ /dev/null @@ -1,566 +0,0 @@ -package terraform - -import ( - "sync" - "testing" - - "github.com/davecgh/go-spew/spew" - "github.com/zclconf/go-cty/cty" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/lang/marks" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -func TestEvaluatorGetTerraformAttr(t *testing.T) { - evaluator := &Evaluator{ - Meta: &ContextMeta{ - Env: "foo", - }, - } - data := &evaluationStateData{ - Evaluator: evaluator, - } - scope := evaluator.Scope(data, nil) - - t.Run("workspace", func(t *testing.T) { - want := cty.StringVal("foo") - got, diags := scope.Data.GetTerraformAttr(addrs.TerraformAttr{ - Name: "workspace", - }, tfdiags.SourceRange{}) - if len(diags) != 0 { - t.Errorf("unexpected diagnostics %s", spew.Sdump(diags)) - } - if !got.RawEquals(want) { - t.Errorf("wrong result %q; want %q", got, want) - } - }) -} - -func TestEvaluatorGetPathAttr(t *testing.T) { - evaluator := &Evaluator{ - Meta: &ContextMeta{ - Env: "foo", - }, - Config: &configs.Config{ - Module: &configs.Module{ - SourceDir: "bar/baz", - }, - }, - } - data := &evaluationStateData{ - Evaluator: evaluator, - } - scope := evaluator.Scope(data, nil) - - t.Run("module", func(t *testing.T) { - want := cty.StringVal("bar/baz") - got, diags := scope.Data.GetPathAttr(addrs.PathAttr{ - Name: "module", - }, tfdiags.SourceRange{}) - if len(diags) != 0 { - t.Errorf("unexpected diagnostics %s", spew.Sdump(diags)) - } - if !got.RawEquals(want) { - t.Errorf("wrong result %#v; want %#v", got, want) - } - }) - - t.Run("root", func(t *testing.T) { - want := cty.StringVal("bar/baz") - got, diags := scope.Data.GetPathAttr(addrs.PathAttr{ - Name: "root", - }, tfdiags.SourceRange{}) - if len(diags) != 0 { - t.Errorf("unexpected diagnostics %s", spew.Sdump(diags)) - } - if !got.RawEquals(want) { - t.Errorf("wrong result %#v; want %#v", got, want) - } - }) -} - -// This particularly tests that a sensitive attribute in config -// results in a value that has a "sensitive" cty Mark -func TestEvaluatorGetInputVariable(t *testing.T) { - evaluator := &Evaluator{ - Meta: &ContextMeta{ - Env: "foo", - }, - Config: &configs.Config{ - Module: &configs.Module{ - Variables: map[string]*configs.Variable{ - "some_var": { - Name: "some_var", - Sensitive: true, - Default: cty.StringVal("foo"), - Type: cty.String, - ConstraintType: cty.String, - }, - // Avoid double marking a value - "some_other_var": { - Name: "some_other_var", - Sensitive: true, - Default: cty.StringVal("bar"), - Type: cty.String, - ConstraintType: cty.String, - }, - }, - }, - }, - VariableValues: map[string]map[string]cty.Value{ - "": { - "some_var": cty.StringVal("bar"), - "some_other_var": cty.StringVal("boop").Mark(marks.Sensitive), - }, - }, - VariableValuesLock: &sync.Mutex{}, - } - - data := &evaluationStateData{ - Evaluator: evaluator, - } - scope := evaluator.Scope(data, nil) - - want := cty.StringVal("bar").Mark(marks.Sensitive) - got, diags := scope.Data.GetInputVariable(addrs.InputVariable{ - Name: "some_var", - }, tfdiags.SourceRange{}) - - if len(diags) != 0 { - t.Errorf("unexpected diagnostics %s", spew.Sdump(diags)) - } - if !got.RawEquals(want) { - t.Errorf("wrong result %#v; want %#v", got, want) - } - - want = cty.StringVal("boop").Mark(marks.Sensitive) - got, diags = scope.Data.GetInputVariable(addrs.InputVariable{ - Name: "some_other_var", - }, tfdiags.SourceRange{}) - - if len(diags) != 0 { - t.Errorf("unexpected diagnostics %s", spew.Sdump(diags)) - } - if !got.RawEquals(want) { - t.Errorf("wrong result %#v; want %#v", got, want) - } -} - -func TestEvaluatorGetResource(t *testing.T) { - stateSync := states.BuildState(func(ss *states.SyncState) { - ss.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_resource", - Name: "foo", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo", "nesting_list": [{"sensitive_value":"abc"}], "nesting_map": {"foo":{"foo":"x"}}, "nesting_set": [{"baz":"abc"}], "nesting_single": {"boop":"abc"}, "nesting_nesting": {"nesting_list":[{"sensitive_value":"abc"}]}, "value":"hello"}`), - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("test"), - Module: addrs.RootModule, - }, - ) - }).SyncWrapper() - - rc := &configs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_resource", - Name: "foo", - Config: configs.SynthBody("", map[string]cty.Value{ - "id": cty.StringVal("foo"), - }), - Provider: addrs.Provider{ - Hostname: addrs.DefaultProviderRegistryHost, - Namespace: "hashicorp", - Type: "test", - }, - } - - evaluator := &Evaluator{ - Meta: &ContextMeta{ - Env: "foo", - }, - Changes: plans.NewChanges().SyncWrapper(), - Config: &configs.Config{ - Module: &configs.Module{ - ManagedResources: map[string]*configs.Resource{ - "test_resource.foo": rc, - }, - }, - }, - State: stateSync, - Plugins: schemaOnlyProvidersForTesting(map[addrs.Provider]*ProviderSchema{ - addrs.NewDefaultProvider("test"): { - Provider: &configschema.Block{}, - ResourceTypes: map[string]*configschema.Block{ - "test_resource": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - "value": { - Type: cty.String, - Computed: true, - Sensitive: true, - }, - }, - BlockTypes: map[string]*configschema.NestedBlock{ - "nesting_list": { - Block: configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "value": {Type: cty.String, Optional: true}, - "sensitive_value": {Type: cty.String, Optional: true, Sensitive: true}, - }, - }, - Nesting: configschema.NestingList, - }, - "nesting_map": { - Block: configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true, Sensitive: true}, - }, - }, - Nesting: configschema.NestingMap, - }, - "nesting_set": { - Block: configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "baz": {Type: cty.String, Optional: true, Sensitive: true}, - }, - }, - Nesting: configschema.NestingSet, - }, - "nesting_single": { - Block: configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "boop": {Type: cty.String, Optional: true, Sensitive: true}, - }, - }, - Nesting: configschema.NestingSingle, - }, - "nesting_nesting": { - Block: configschema.Block{ - BlockTypes: map[string]*configschema.NestedBlock{ - "nesting_list": { - Block: configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "value": {Type: cty.String, Optional: true}, - "sensitive_value": {Type: cty.String, Optional: true, Sensitive: true}, - }, - }, - Nesting: configschema.NestingList, - }, - }, - }, - Nesting: configschema.NestingSingle, - }, - }, - }, - }, - }, - }), - } - - data := &evaluationStateData{ - Evaluator: evaluator, - } - scope := evaluator.Scope(data, nil) - - want := cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("foo"), - "nesting_list": cty.ListVal([]cty.Value{ - cty.ObjectVal(map[string]cty.Value{ - "sensitive_value": cty.StringVal("abc").Mark(marks.Sensitive), - "value": cty.NullVal(cty.String), - }), - }), - "nesting_map": cty.MapVal(map[string]cty.Value{ - "foo": cty.ObjectVal(map[string]cty.Value{"foo": cty.StringVal("x").Mark(marks.Sensitive)}), - }), - "nesting_nesting": cty.ObjectVal(map[string]cty.Value{ - "nesting_list": cty.ListVal([]cty.Value{ - cty.ObjectVal(map[string]cty.Value{ - "sensitive_value": cty.StringVal("abc").Mark(marks.Sensitive), - "value": cty.NullVal(cty.String), - }), - }), - }), - "nesting_set": cty.SetVal([]cty.Value{ - cty.ObjectVal(map[string]cty.Value{ - "baz": cty.StringVal("abc").Mark(marks.Sensitive), - }), - }), - "nesting_single": cty.ObjectVal(map[string]cty.Value{ - "boop": cty.StringVal("abc").Mark(marks.Sensitive), - }), - "value": cty.StringVal("hello").Mark(marks.Sensitive), - }) - - addr := addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_resource", - Name: "foo", - } - got, diags := scope.Data.GetResource(addr, tfdiags.SourceRange{}) - - if len(diags) != 0 { - t.Errorf("unexpected diagnostics %s", spew.Sdump(diags)) - } - - if !got.RawEquals(want) { - t.Errorf("wrong result:\ngot: %#v\nwant: %#v", got, want) - } -} - -// GetResource will return a planned object's After value -// if there is a change for that resource instance. -func TestEvaluatorGetResource_changes(t *testing.T) { - // Set up existing state - stateSync := states.BuildState(func(ss *states.SyncState) { - ss.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_resource", - Name: "foo", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectPlanned, - AttrsJSON: []byte(`{"id":"foo", "to_mark_val":"tacos", "sensitive_value":"abc"}`), - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("test"), - Module: addrs.RootModule, - }, - ) - }).SyncWrapper() - - // Create a change for the existing state resource, - // to exercise retrieving the After value of the change - changesSync := plans.NewChanges().SyncWrapper() - change := &plans.ResourceInstanceChange{ - Addr: mustResourceInstanceAddr("test_resource.foo"), - ProviderAddr: addrs.AbsProviderConfig{ - Module: addrs.RootModule, - Provider: addrs.NewDefaultProvider("test"), - }, - Change: plans.Change{ - Action: plans.Update, - // Provide an After value that contains a marked value - After: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("foo"), - "to_mark_val": cty.StringVal("pizza").Mark(marks.Sensitive), - "sensitive_value": cty.StringVal("abc"), - "sensitive_collection": cty.MapVal(map[string]cty.Value{ - "boop": cty.StringVal("beep"), - }), - }), - }, - } - - // Set up our schemas - schemas := &Schemas{ - Providers: map[addrs.Provider]*ProviderSchema{ - addrs.NewDefaultProvider("test"): { - Provider: &configschema.Block{}, - ResourceTypes: map[string]*configschema.Block{ - "test_resource": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - "to_mark_val": { - Type: cty.String, - Computed: true, - }, - "sensitive_value": { - Type: cty.String, - Computed: true, - Sensitive: true, - }, - "sensitive_collection": { - Type: cty.Map(cty.String), - Computed: true, - Sensitive: true, - }, - }, - }, - }, - }, - }, - } - - // The resource we'll inspect - addr := addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_resource", - Name: "foo", - } - schema, _ := schemas.ResourceTypeConfig(addrs.NewDefaultProvider("test"), addr.Mode, addr.Type) - // This encoding separates out the After's marks into its AfterValMarks - csrc, _ := change.Encode(schema.ImpliedType()) - changesSync.AppendResourceInstanceChange(csrc) - - evaluator := &Evaluator{ - Meta: &ContextMeta{ - Env: "foo", - }, - Changes: changesSync, - Config: &configs.Config{ - Module: &configs.Module{ - ManagedResources: map[string]*configs.Resource{ - "test_resource.foo": { - Mode: addrs.ManagedResourceMode, - Type: "test_resource", - Name: "foo", - Provider: addrs.Provider{ - Hostname: addrs.DefaultProviderRegistryHost, - Namespace: "hashicorp", - Type: "test", - }, - }, - }, - }, - }, - State: stateSync, - Plugins: schemaOnlyProvidersForTesting(schemas.Providers), - } - - data := &evaluationStateData{ - Evaluator: evaluator, - } - scope := evaluator.Scope(data, nil) - - want := cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("foo"), - "to_mark_val": cty.StringVal("pizza").Mark(marks.Sensitive), - "sensitive_value": cty.StringVal("abc").Mark(marks.Sensitive), - "sensitive_collection": cty.MapVal(map[string]cty.Value{ - "boop": cty.StringVal("beep"), - }).Mark(marks.Sensitive), - }) - - got, diags := scope.Data.GetResource(addr, tfdiags.SourceRange{}) - - if len(diags) != 0 { - t.Errorf("unexpected diagnostics %s", spew.Sdump(diags)) - } - - if !got.RawEquals(want) { - t.Errorf("wrong result:\ngot: %#v\nwant: %#v", got, want) - } -} - -func TestEvaluatorGetModule(t *testing.T) { - // Create a new evaluator with an existing state - stateSync := states.BuildState(func(ss *states.SyncState) { - ss.SetOutputValue( - addrs.OutputValue{Name: "out"}.Absolute(addrs.ModuleInstance{addrs.ModuleInstanceStep{Name: "mod"}}), - cty.StringVal("bar"), - true, - ) - }).SyncWrapper() - evaluator := evaluatorForModule(stateSync, plans.NewChanges().SyncWrapper()) - data := &evaluationStateData{ - Evaluator: evaluator, - } - scope := evaluator.Scope(data, nil) - want := cty.ObjectVal(map[string]cty.Value{"out": cty.StringVal("bar").Mark(marks.Sensitive)}) - got, diags := scope.Data.GetModule(addrs.ModuleCall{ - Name: "mod", - }, tfdiags.SourceRange{}) - - if len(diags) != 0 { - t.Errorf("unexpected diagnostics %s", spew.Sdump(diags)) - } - if !got.RawEquals(want) { - t.Errorf("wrong result %#v; want %#v", got, want) - } - - // Changes should override the state value - changesSync := plans.NewChanges().SyncWrapper() - change := &plans.OutputChange{ - Addr: addrs.OutputValue{Name: "out"}.Absolute(addrs.ModuleInstance{addrs.ModuleInstanceStep{Name: "mod"}}), - Sensitive: true, - Change: plans.Change{ - After: cty.StringVal("baz"), - }, - } - cs, _ := change.Encode() - changesSync.AppendOutputChange(cs) - evaluator = evaluatorForModule(stateSync, changesSync) - data = &evaluationStateData{ - Evaluator: evaluator, - } - scope = evaluator.Scope(data, nil) - want = cty.ObjectVal(map[string]cty.Value{"out": cty.StringVal("baz").Mark(marks.Sensitive)}) - got, diags = scope.Data.GetModule(addrs.ModuleCall{ - Name: "mod", - }, tfdiags.SourceRange{}) - - if len(diags) != 0 { - t.Errorf("unexpected diagnostics %s", spew.Sdump(diags)) - } - if !got.RawEquals(want) { - t.Errorf("wrong result %#v; want %#v", got, want) - } - - // Test changes with empty state - evaluator = evaluatorForModule(states.NewState().SyncWrapper(), changesSync) - data = &evaluationStateData{ - Evaluator: evaluator, - } - scope = evaluator.Scope(data, nil) - want = cty.ObjectVal(map[string]cty.Value{"out": cty.StringVal("baz").Mark(marks.Sensitive)}) - got, diags = scope.Data.GetModule(addrs.ModuleCall{ - Name: "mod", - }, tfdiags.SourceRange{}) - - if len(diags) != 0 { - t.Errorf("unexpected diagnostics %s", spew.Sdump(diags)) - } - if !got.RawEquals(want) { - t.Errorf("wrong result %#v; want %#v", got, want) - } -} - -func evaluatorForModule(stateSync *states.SyncState, changesSync *plans.ChangesSync) *Evaluator { - return &Evaluator{ - Meta: &ContextMeta{ - Env: "foo", - }, - Config: &configs.Config{ - Module: &configs.Module{ - ModuleCalls: map[string]*configs.ModuleCall{ - "mod": { - Name: "mod", - }, - }, - }, - Children: map[string]*configs.Config{ - "mod": { - Path: addrs.Module{"module.mod"}, - Module: &configs.Module{ - Outputs: map[string]*configs.Output{ - "out": { - Name: "out", - Sensitive: true, - }, - }, - }, - }, - }, - }, - State: stateSync, - Changes: changesSync, - } -} diff --git a/internal/terraform/evaluate_triggers.go b/internal/terraform/evaluate_triggers.go deleted file mode 100644 index 31fd80e16b2d..000000000000 --- a/internal/terraform/evaluate_triggers.go +++ /dev/null @@ -1,143 +0,0 @@ -package terraform - -import ( - "strings" - - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/instances" - "github.com/hashicorp/terraform/internal/tfdiags" - "github.com/zclconf/go-cty/cty" -) - -func evalReplaceTriggeredByExpr(expr hcl.Expression, keyData instances.RepetitionData) (*addrs.Reference, tfdiags.Diagnostics) { - var ref *addrs.Reference - var diags tfdiags.Diagnostics - - traversal, diags := triggersExprToTraversal(expr, keyData) - if diags.HasErrors() { - return nil, diags - } - - // We now have a static traversal, so we can just turn it into an addrs.Reference. - ref, ds := addrs.ParseRef(traversal) - diags = diags.Append(ds) - - return ref, diags -} - -// trggersExprToTraversal takes an hcl expression limited to the syntax allowed -// in replace_triggered_by, and converts it to a static traversal. The -// RepetitionData contains the data necessary to evaluate the only allowed -// variables in the expression, count.index and each.key. -func triggersExprToTraversal(expr hcl.Expression, keyData instances.RepetitionData) (hcl.Traversal, tfdiags.Diagnostics) { - var trav hcl.Traversal - var diags tfdiags.Diagnostics - - switch e := expr.(type) { - case *hclsyntax.RelativeTraversalExpr: - t, d := triggersExprToTraversal(e.Source, keyData) - diags = diags.Append(d) - trav = append(trav, t...) - trav = append(trav, e.Traversal...) - - case *hclsyntax.ScopeTraversalExpr: - // a static reference, we can just append the traversal - trav = append(trav, e.Traversal...) - - case *hclsyntax.IndexExpr: - // Get the collection from the index expression - t, d := triggersExprToTraversal(e.Collection, keyData) - diags = diags.Append(d) - if diags.HasErrors() { - return nil, diags - } - trav = append(trav, t...) - - // The index key is the only place where we could have variables that - // reference count and each, so we need to parse those independently. - idx, hclDiags := parseIndexKeyExpr(e.Key, keyData) - diags = diags.Append(hclDiags) - - trav = append(trav, idx) - - default: - // Something unexpected got through config validation. We're not sure - // what it is, but we'll point it out in the diagnostics for the user - // to fix. - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid replace_triggered_by expression", - Detail: "Unexpected expression found in replace_triggered_by.", - Subject: e.Range().Ptr(), - }) - } - - return trav, diags -} - -// parseIndexKeyExpr takes an hcl.Expression and parses it as an index key, while -// evaluating any references to count.index or each.key. -func parseIndexKeyExpr(expr hcl.Expression, keyData instances.RepetitionData) (hcl.TraverseIndex, hcl.Diagnostics) { - idx := hcl.TraverseIndex{ - SrcRange: expr.Range(), - } - - trav, diags := hcl.RelTraversalForExpr(expr) - if diags.HasErrors() { - return idx, diags - } - - keyParts := []string{} - - for _, t := range trav { - attr, ok := t.(hcl.TraverseAttr) - if !ok { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid index expression", - Detail: "Only constant values, count.index or each.key are allowed in index expressions.", - Subject: expr.Range().Ptr(), - }) - return idx, diags - } - keyParts = append(keyParts, attr.Name) - } - - switch strings.Join(keyParts, ".") { - case "count.index": - if keyData.CountIndex == cty.NilVal { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: `Reference to "count" in non-counted context`, - Detail: `The "count" object can only be used in "resource" blocks when the "count" argument is set.`, - Subject: expr.Range().Ptr(), - }) - } - idx.Key = keyData.CountIndex - - case "each.key": - if keyData.EachKey == cty.NilVal { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: `Reference to "each" in context without for_each`, - Detail: `The "each" object can be used only in "resource" blocks when the "for_each" argument is set.`, - Subject: expr.Range().Ptr(), - }) - } - idx.Key = keyData.EachKey - default: - // Something may have slipped through validation, probably from a json - // configuration. - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid index expression", - Detail: "Only constant values, count.index or each.key are allowed in index expressions.", - Subject: expr.Range().Ptr(), - }) - } - - return idx, diags - -} diff --git a/internal/terraform/evaluate_triggers_test.go b/internal/terraform/evaluate_triggers_test.go deleted file mode 100644 index d51b1c2be6b6..000000000000 --- a/internal/terraform/evaluate_triggers_test.go +++ /dev/null @@ -1,94 +0,0 @@ -package terraform - -import ( - "testing" - - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/instances" - "github.com/zclconf/go-cty/cty" -) - -func TestEvalReplaceTriggeredBy(t *testing.T) { - tests := map[string]struct { - // Raw config expression from within replace_triggered_by list. - // If this does not contains any count or each references, it should - // directly parse into the same *addrs.Reference. - expr string - - // If the expression contains count or each, then we need to add - // repetition data, and the static string to parse into the desired - // *addrs.Reference - repData instances.RepetitionData - reference string - }{ - "single resource": { - expr: "test_resource.a", - }, - - "resource instance attr": { - expr: "test_resource.a.attr", - }, - - "resource instance index attr": { - expr: "test_resource.a[0].attr", - }, - - "resource instance count": { - expr: "test_resource.a[count.index]", - repData: instances.RepetitionData{ - CountIndex: cty.NumberIntVal(0), - }, - reference: "test_resource.a[0]", - }, - "resource instance for_each": { - expr: "test_resource.a[each.key].attr", - repData: instances.RepetitionData{ - EachKey: cty.StringVal("k"), - }, - reference: `test_resource.a["k"].attr`, - }, - "resource instance for_each map attr": { - expr: "test_resource.a[each.key].attr[each.key]", - repData: instances.RepetitionData{ - EachKey: cty.StringVal("k"), - }, - reference: `test_resource.a["k"].attr["k"]`, - }, - } - - for name, tc := range tests { - pos := hcl.Pos{Line: 1, Column: 1} - t.Run(name, func(t *testing.T) { - expr, hclDiags := hclsyntax.ParseExpression([]byte(tc.expr), "", pos) - if hclDiags.HasErrors() { - t.Fatal(hclDiags) - } - - got, diags := evalReplaceTriggeredByExpr(expr, tc.repData) - if diags.HasErrors() { - t.Fatal(diags.Err()) - } - - want := tc.reference - if want == "" { - want = tc.expr - } - - // create the desired reference - traversal, travDiags := hclsyntax.ParseTraversalAbs([]byte(want), "", pos) - if travDiags.HasErrors() { - t.Fatal(travDiags) - } - ref, diags := addrs.ParseRef(traversal) - if diags.HasErrors() { - t.Fatal(diags.Err()) - } - - if got.DisplayString() != ref.DisplayString() { - t.Fatalf("expected %q: got %q", ref.DisplayString(), got.DisplayString()) - } - }) - } -} diff --git a/internal/terraform/evaluate_valid.go b/internal/terraform/evaluate_valid.go deleted file mode 100644 index 1d43cc4fce64..000000000000 --- a/internal/terraform/evaluate_valid.go +++ /dev/null @@ -1,318 +0,0 @@ -package terraform - -import ( - "fmt" - "sort" - - "github.com/hashicorp/hcl/v2" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/didyoumean" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -// StaticValidateReferences checks the given references against schemas and -// other statically-checkable rules, producing error diagnostics if any -// problems are found. -// -// If this method returns errors for a particular reference then evaluating -// that reference is likely to generate a very similar error, so callers should -// not run this method and then also evaluate the source expression(s) and -// merge the two sets of diagnostics together, since this will result in -// confusing redundant errors. -// -// This method can find more errors than can be found by evaluating an -// expression with a partially-populated scope, since it checks the referenced -// names directly against the schema rather than relying on evaluation errors. -// -// The result may include warning diagnostics if, for example, deprecated -// features are referenced. -func (d *evaluationStateData) StaticValidateReferences(refs []*addrs.Reference, self addrs.Referenceable) tfdiags.Diagnostics { - var diags tfdiags.Diagnostics - for _, ref := range refs { - moreDiags := d.staticValidateReference(ref, self) - diags = diags.Append(moreDiags) - } - return diags -} - -func (d *evaluationStateData) staticValidateReference(ref *addrs.Reference, self addrs.Referenceable) tfdiags.Diagnostics { - modCfg := d.Evaluator.Config.DescendentForInstance(d.ModulePath) - if modCfg == nil { - // This is a bug in the caller rather than a problem with the - // reference, but rather than crashing out here in an unhelpful way - // we'll just ignore it and trust a different layer to catch it. - return nil - } - - if ref.Subject == addrs.Self { - // The "self" address is a special alias for the address given as - // our self parameter here, if present. - if self == nil { - var diags tfdiags.Diagnostics - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: `Invalid "self" reference`, - // This detail message mentions some current practice that - // this codepath doesn't really "know about". If the "self" - // object starts being supported in more contexts later then - // we'll need to adjust this message. - Detail: `The "self" object is not available in this context. This object can be used only in resource provisioner, connection, and postcondition blocks.`, - Subject: ref.SourceRange.ToHCL().Ptr(), - }) - return diags - } - - synthRef := *ref // shallow copy - synthRef.Subject = self - ref = &synthRef - } - - switch addr := ref.Subject.(type) { - - // For static validation we validate both resource and resource instance references the same way. - // We mostly disregard the index, though we do some simple validation of - // its _presence_ in staticValidateSingleResourceReference and - // staticValidateMultiResourceReference respectively. - case addrs.Resource: - var diags tfdiags.Diagnostics - diags = diags.Append(d.staticValidateSingleResourceReference(modCfg, addr, ref.Remaining, ref.SourceRange)) - diags = diags.Append(d.staticValidateResourceReference(modCfg, addr, ref.Remaining, ref.SourceRange)) - return diags - case addrs.ResourceInstance: - var diags tfdiags.Diagnostics - diags = diags.Append(d.staticValidateMultiResourceReference(modCfg, addr, ref.Remaining, ref.SourceRange)) - diags = diags.Append(d.staticValidateResourceReference(modCfg, addr.ContainingResource(), ref.Remaining, ref.SourceRange)) - return diags - - // We also handle all module call references the same way, disregarding index. - case addrs.ModuleCall: - return d.staticValidateModuleCallReference(modCfg, addr, ref.Remaining, ref.SourceRange) - case addrs.ModuleCallInstance: - return d.staticValidateModuleCallReference(modCfg, addr.Call, ref.Remaining, ref.SourceRange) - case addrs.ModuleCallInstanceOutput: - // This one is a funny one because we will take the output name referenced - // and use it to fake up a "remaining" that would make sense for the - // module call itself, rather than for the specific output, and then - // we can just re-use our static module call validation logic. - remain := make(hcl.Traversal, len(ref.Remaining)+1) - copy(remain[1:], ref.Remaining) - remain[0] = hcl.TraverseAttr{ - Name: addr.Name, - - // Using the whole reference as the source range here doesn't exactly - // match how HCL would normally generate an attribute traversal, - // but is close enough for our purposes. - SrcRange: ref.SourceRange.ToHCL(), - } - return d.staticValidateModuleCallReference(modCfg, addr.Call.Call, remain, ref.SourceRange) - - default: - // Anything else we'll just permit through without any static validation - // and let it be caught during dynamic evaluation, in evaluate.go . - return nil - } -} - -func (d *evaluationStateData) staticValidateSingleResourceReference(modCfg *configs.Config, addr addrs.Resource, remain hcl.Traversal, rng tfdiags.SourceRange) tfdiags.Diagnostics { - // If we have at least one step in "remain" and this resource has - // "count" set then we know for sure this in invalid because we have - // something like: - // aws_instance.foo.bar - // ...when we really need - // aws_instance.foo[count.index].bar - - // It is _not_ safe to do this check when remain is empty, because that - // would also match aws_instance.foo[count.index].bar due to `count.index` - // not being statically-resolvable as part of a reference, and match - // direct references to the whole aws_instance.foo tuple. - if len(remain) == 0 { - return nil - } - - var diags tfdiags.Diagnostics - - cfg := modCfg.Module.ResourceByAddr(addr) - if cfg == nil { - // We'll just bail out here and catch this in our subsequent call to - // staticValidateResourceReference, then. - return diags - } - - if cfg.Count != nil { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: `Missing resource instance key`, - Detail: fmt.Sprintf("Because %s has \"count\" set, its attributes must be accessed on specific instances.\n\nFor example, to correlate with indices of a referring resource, use:\n %s[count.index]", addr, addr), - Subject: rng.ToHCL().Ptr(), - }) - } - if cfg.ForEach != nil { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: `Missing resource instance key`, - Detail: fmt.Sprintf("Because %s has \"for_each\" set, its attributes must be accessed on specific instances.\n\nFor example, to correlate with indices of a referring resource, use:\n %s[each.key]", addr, addr), - Subject: rng.ToHCL().Ptr(), - }) - } - - return diags -} - -func (d *evaluationStateData) staticValidateMultiResourceReference(modCfg *configs.Config, addr addrs.ResourceInstance, remain hcl.Traversal, rng tfdiags.SourceRange) tfdiags.Diagnostics { - var diags tfdiags.Diagnostics - - cfg := modCfg.Module.ResourceByAddr(addr.ContainingResource()) - if cfg == nil { - // We'll just bail out here and catch this in our subsequent call to - // staticValidateResourceReference, then. - return diags - } - - if addr.Key == addrs.NoKey { - // This is a different path into staticValidateSingleResourceReference - return d.staticValidateSingleResourceReference(modCfg, addr.ContainingResource(), remain, rng) - } else { - if cfg.Count == nil && cfg.ForEach == nil { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: `Unexpected resource instance key`, - Detail: fmt.Sprintf(`Because %s does not have "count" or "for_each" set, references to it must not include an index key. Remove the bracketed index to refer to the single instance of this resource.`, addr.ContainingResource()), - Subject: rng.ToHCL().Ptr(), - }) - } - } - - return diags -} - -func (d *evaluationStateData) staticValidateResourceReference(modCfg *configs.Config, addr addrs.Resource, remain hcl.Traversal, rng tfdiags.SourceRange) tfdiags.Diagnostics { - var diags tfdiags.Diagnostics - - var modeAdjective string - switch addr.Mode { - case addrs.ManagedResourceMode: - modeAdjective = "managed" - case addrs.DataResourceMode: - modeAdjective = "data" - default: - // should never happen - modeAdjective = "" - } - - cfg := modCfg.Module.ResourceByAddr(addr) - if cfg == nil { - var suggestion string - // A common mistake is omitting the data. prefix when trying to refer - // to a data resource, so we'll add a special hint for that. - if addr.Mode == addrs.ManagedResourceMode { - candidateAddr := addr // not a pointer, so this is a copy - candidateAddr.Mode = addrs.DataResourceMode - if candidateCfg := modCfg.Module.ResourceByAddr(candidateAddr); candidateCfg != nil { - suggestion = fmt.Sprintf("\n\nDid you mean the data resource %s?", candidateAddr) - } - } - - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: `Reference to undeclared resource`, - Detail: fmt.Sprintf(`A %s resource %q %q has not been declared in %s.%s`, modeAdjective, addr.Type, addr.Name, moduleConfigDisplayAddr(modCfg.Path), suggestion), - Subject: rng.ToHCL().Ptr(), - }) - return diags - } - - providerFqn := modCfg.Module.ProviderForLocalConfig(cfg.ProviderConfigAddr()) - schema, _, err := d.Evaluator.Plugins.ResourceTypeSchema(providerFqn, addr.Mode, addr.Type) - if err != nil { - // Prior validation should've taken care of a schema lookup error, - // so we should never get here but we'll handle it here anyway for - // robustness. - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: `Failed provider schema lookup`, - Detail: fmt.Sprintf(`Couldn't load schema for %s resource type %q in %s: %s.`, modeAdjective, addr.Type, providerFqn.String(), err), - Subject: rng.ToHCL().Ptr(), - }) - } - - if schema == nil { - // Prior validation should've taken care of a resource block with an - // unsupported type, so we should never get here but we'll handle it - // here anyway for robustness. - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: `Invalid resource type`, - Detail: fmt.Sprintf(`A %s resource type %q is not supported by provider %q.`, modeAdjective, addr.Type, providerFqn.String()), - Subject: rng.ToHCL().Ptr(), - }) - return diags - } - - // As a special case we'll detect attempts to access an attribute called - // "count" and produce a special error for it, since versions of Terraform - // prior to v0.12 offered this as a weird special case that we can no - // longer support. - if len(remain) > 0 { - if step, ok := remain[0].(hcl.TraverseAttr); ok && step.Name == "count" { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: `Invalid resource count attribute`, - Detail: fmt.Sprintf(`The special "count" attribute is no longer supported after Terraform v0.12. Instead, use length(%s) to count resource instances.`, addr), - Subject: rng.ToHCL().Ptr(), - }) - return diags - } - } - - // If we got this far then we'll try to validate the remaining traversal - // steps against our schema. - moreDiags := schema.StaticValidateTraversal(remain) - diags = diags.Append(moreDiags) - - return diags -} - -func (d *evaluationStateData) staticValidateModuleCallReference(modCfg *configs.Config, addr addrs.ModuleCall, remain hcl.Traversal, rng tfdiags.SourceRange) tfdiags.Diagnostics { - var diags tfdiags.Diagnostics - - // For now, our focus here is just in testing that the referenced module - // call exists. All other validation is deferred until evaluation time. - _, exists := modCfg.Module.ModuleCalls[addr.Name] - if !exists { - var suggestions []string - for name := range modCfg.Module.ModuleCalls { - suggestions = append(suggestions, name) - } - sort.Strings(suggestions) - suggestion := didyoumean.NameSuggestion(addr.Name, suggestions) - if suggestion != "" { - suggestion = fmt.Sprintf(" Did you mean %q?", suggestion) - } - - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: `Reference to undeclared module`, - Detail: fmt.Sprintf(`No module call named %q is declared in %s.%s`, addr.Name, moduleConfigDisplayAddr(modCfg.Path), suggestion), - Subject: rng.ToHCL().Ptr(), - }) - return diags - } - - return diags -} - -// moduleConfigDisplayAddr returns a string describing the given module -// address that is appropriate for returning to users in situations where the -// root module is possible. Specifically, it returns "the root module" if the -// root module instance is given, or a string representation of the module -// address otherwise. -func moduleConfigDisplayAddr(addr addrs.Module) string { - switch { - case addr.IsRoot(): - return "the root module" - default: - return addr.String() - } -} diff --git a/internal/terraform/evaluate_valid_test.go b/internal/terraform/evaluate_valid_test.go deleted file mode 100644 index cfdfdea1f5e1..000000000000 --- a/internal/terraform/evaluate_valid_test.go +++ /dev/null @@ -1,121 +0,0 @@ -package terraform - -import ( - "testing" - - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/hcl/v2/hclsyntax" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/lang" -) - -func TestStaticValidateReferences(t *testing.T) { - tests := []struct { - Ref string - WantErr string - }{ - { - "aws_instance.no_count", - ``, - }, - { - "aws_instance.count", - ``, - }, - { - "aws_instance.count[0]", - ``, - }, - { - "aws_instance.nonexist", - `Reference to undeclared resource: A managed resource "aws_instance" "nonexist" has not been declared in the root module.`, - }, - { - "beep.boop", - `Reference to undeclared resource: A managed resource "beep" "boop" has not been declared in the root module. - -Did you mean the data resource data.beep.boop?`, - }, - { - "aws_instance.no_count[0]", - `Unexpected resource instance key: Because aws_instance.no_count does not have "count" or "for_each" set, references to it must not include an index key. Remove the bracketed index to refer to the single instance of this resource.`, - }, - { - "aws_instance.count.foo", - // In this case we return two errors that are somewhat redundant with - // one another, but we'll accept that because they both report the - // problem from different perspectives and so give the user more - // opportunity to understand what's going on here. - `2 problems: - -- Missing resource instance key: Because aws_instance.count has "count" set, its attributes must be accessed on specific instances. - -For example, to correlate with indices of a referring resource, use: - aws_instance.count[count.index] -- Unsupported attribute: This object has no argument, nested block, or exported attribute named "foo".`, - }, - { - "boop_instance.yep", - ``, - }, - { - "boop_whatever.nope", - `Invalid resource type: A managed resource type "boop_whatever" is not supported by provider "registry.terraform.io/foobar/beep".`, - }, - } - - cfg := testModule(t, "static-validate-refs") - evaluator := &Evaluator{ - Config: cfg, - Plugins: schemaOnlyProvidersForTesting(map[addrs.Provider]*ProviderSchema{ - addrs.NewDefaultProvider("aws"): { - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": {}, - }, - }, - addrs.MustParseProviderSourceString("foobar/beep"): { - ResourceTypes: map[string]*configschema.Block{ - // intentional mismatch between resource type prefix and provider type - "boop_instance": {}, - }, - }, - }), - } - - for _, test := range tests { - t.Run(test.Ref, func(t *testing.T) { - traversal, hclDiags := hclsyntax.ParseTraversalAbs([]byte(test.Ref), "", hcl.Pos{Line: 1, Column: 1}) - if hclDiags.HasErrors() { - t.Fatal(hclDiags.Error()) - } - - refs, diags := lang.References([]hcl.Traversal{traversal}) - if diags.HasErrors() { - t.Fatal(diags.Err()) - } - - data := &evaluationStateData{ - Evaluator: evaluator, - } - - diags = data.StaticValidateReferences(refs, nil) - if diags.HasErrors() { - if test.WantErr == "" { - t.Fatalf("Unexpected diagnostics: %s", diags.Err()) - } - - gotErr := diags.Err().Error() - if gotErr != test.WantErr { - t.Fatalf("Wrong diagnostics\ngot: %s\nwant: %s", gotErr, test.WantErr) - } - return - } - - if test.WantErr != "" { - t.Fatalf("Expected diagnostics, but got none\nwant: %s", test.WantErr) - } - }) - } -} diff --git a/internal/terraform/execute.go b/internal/terraform/execute.go deleted file mode 100644 index 8c3a6fe15e0c..000000000000 --- a/internal/terraform/execute.go +++ /dev/null @@ -1,9 +0,0 @@ -package terraform - -import "github.com/hashicorp/terraform/internal/tfdiags" - -// GraphNodeExecutable is the interface that graph nodes must implement to -// enable execution. -type GraphNodeExecutable interface { - Execute(EvalContext, walkOperation) tfdiags.Diagnostics -} diff --git a/internal/terraform/features.go b/internal/terraform/features.go deleted file mode 100644 index 97c77bdbd001..000000000000 --- a/internal/terraform/features.go +++ /dev/null @@ -1,7 +0,0 @@ -package terraform - -import "os" - -// This file holds feature flags for the next release - -var flagWarnOutputErrors = os.Getenv("TF_WARN_OUTPUT_ERRORS") != "" diff --git a/internal/terraform/graph.go b/internal/terraform/graph.go deleted file mode 100644 index 38d0fad6ed5c..000000000000 --- a/internal/terraform/graph.go +++ /dev/null @@ -1,135 +0,0 @@ -package terraform - -import ( - "fmt" - "log" - "strings" - - "github.com/hashicorp/terraform/internal/logging" - "github.com/hashicorp/terraform/internal/tfdiags" - - "github.com/hashicorp/terraform/internal/addrs" - - "github.com/hashicorp/terraform/internal/dag" -) - -// Graph represents the graph that Terraform uses to represent resources -// and their dependencies. -type Graph struct { - // Graph is the actual DAG. This is embedded so you can call the DAG - // methods directly. - dag.AcyclicGraph - - // Path is the path in the module tree that this Graph represents. - Path addrs.ModuleInstance -} - -func (g *Graph) DirectedGraph() dag.Grapher { - return &g.AcyclicGraph -} - -// Walk walks the graph with the given walker for callbacks. The graph -// will be walked with full parallelism, so the walker should expect -// to be called in concurrently. -func (g *Graph) Walk(walker GraphWalker) tfdiags.Diagnostics { - return g.walk(walker) -} - -func (g *Graph) walk(walker GraphWalker) tfdiags.Diagnostics { - // The callbacks for enter/exiting a graph - ctx := walker.EvalContext() - - // Walk the graph. - walkFn := func(v dag.Vertex) (diags tfdiags.Diagnostics) { - // the walkFn is called asynchronously, and needs to be recovered - // separately in the case of a panic. - defer logging.PanicHandler() - - log.Printf("[TRACE] vertex %q: starting visit (%T)", dag.VertexName(v), v) - - defer func() { - if diags.HasErrors() { - for _, diag := range diags { - if diag.Severity() == tfdiags.Error { - desc := diag.Description() - log.Printf("[ERROR] vertex %q error: %s", dag.VertexName(v), desc.Summary) - } - } - log.Printf("[TRACE] vertex %q: visit complete, with errors", dag.VertexName(v)) - } else { - log.Printf("[TRACE] vertex %q: visit complete", dag.VertexName(v)) - } - }() - - // vertexCtx is the context that we use when evaluating. This - // is normally the context of our graph but can be overridden - // with a GraphNodeModuleInstance impl. - vertexCtx := ctx - if pn, ok := v.(GraphNodeModuleInstance); ok { - vertexCtx = walker.EnterPath(pn.Path()) - defer walker.ExitPath(pn.Path()) - } - - // If the node is exec-able, then execute it. - if ev, ok := v.(GraphNodeExecutable); ok { - diags = diags.Append(walker.Execute(vertexCtx, ev)) - if diags.HasErrors() { - return - } - } - - // If the node is dynamically expanded, then expand it - if ev, ok := v.(GraphNodeDynamicExpandable); ok { - log.Printf("[TRACE] vertex %q: expanding dynamic subgraph", dag.VertexName(v)) - - g, err := ev.DynamicExpand(vertexCtx) - diags = diags.Append(err) - if diags.HasErrors() { - log.Printf("[TRACE] vertex %q: failed expanding dynamic subgraph: %s", dag.VertexName(v), err) - return - } - if g != nil { - // The subgraph should always be valid, per our normal acyclic - // graph validation rules. - if err := g.Validate(); err != nil { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Graph node has invalid dynamic subgraph", - fmt.Sprintf("The internal logic for %q generated an invalid dynamic subgraph: %s.\n\nThis is a bug in Terraform. Please report it!", dag.VertexName(v), err), - )) - return - } - // If we passed validation then there is exactly one root node. - // That root node should always be "rootNode", the singleton - // root node value. - if n, err := g.Root(); err != nil || n != dag.Vertex(rootNode) { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Graph node has invalid dynamic subgraph", - fmt.Sprintf("The internal logic for %q generated an invalid dynamic subgraph: the root node is %T, which is not a suitable root node type.\n\nThis is a bug in Terraform. Please report it!", dag.VertexName(v), n), - )) - return - } - - // Walk the subgraph - log.Printf("[TRACE] vertex %q: entering dynamic subgraph", dag.VertexName(v)) - subDiags := g.walk(walker) - diags = diags.Append(subDiags) - if subDiags.HasErrors() { - var errs []string - for _, d := range subDiags { - errs = append(errs, d.Description().Summary) - } - log.Printf("[TRACE] vertex %q: dynamic subgraph encountered errors: %s", dag.VertexName(v), strings.Join(errs, ",")) - return - } - log.Printf("[TRACE] vertex %q: dynamic subgraph completed successfully", dag.VertexName(v)) - } else { - log.Printf("[TRACE] vertex %q: produced no dynamic subgraph", dag.VertexName(v)) - } - } - return - } - - return g.AcyclicGraph.Walk(walkFn) -} diff --git a/internal/terraform/graph_builder.go b/internal/terraform/graph_builder.go deleted file mode 100644 index 1c69ee41f82d..000000000000 --- a/internal/terraform/graph_builder.go +++ /dev/null @@ -1,65 +0,0 @@ -package terraform - -import ( - "log" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/logging" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -// GraphBuilder is an interface that can be implemented and used with -// Terraform to build the graph that Terraform walks. -type GraphBuilder interface { - // Build builds the graph for the given module path. It is up to - // the interface implementation whether this build should expand - // the graph or not. - Build(addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics) -} - -// BasicGraphBuilder is a GraphBuilder that builds a graph out of a -// series of transforms and (optionally) validates the graph is a valid -// structure. -type BasicGraphBuilder struct { - Steps []GraphTransformer - // Optional name to add to the graph debug log - Name string -} - -func (b *BasicGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - g := &Graph{Path: path} - - var lastStepStr string - for _, step := range b.Steps { - if step == nil { - continue - } - log.Printf("[TRACE] Executing graph transform %T", step) - - err := step.Transform(g) - if thisStepStr := g.StringWithNodeTypes(); thisStepStr != lastStepStr { - log.Printf("[TRACE] Completed graph transform %T with new graph:\n%s ------", step, logging.Indent(thisStepStr)) - lastStepStr = thisStepStr - } else { - log.Printf("[TRACE] Completed graph transform %T (no changes)", step) - } - - if err != nil { - if nf, isNF := err.(tfdiags.NonFatalError); isNF { - diags = diags.Append(nf.Diagnostics) - } else { - diags = diags.Append(err) - return g, diags - } - } - } - - if err := g.Validate(); err != nil { - log.Printf("[ERROR] Graph validation failed. Graph:\n\n%s", g.String()) - diags = diags.Append(err) - return nil, diags - } - - return g, diags -} diff --git a/internal/terraform/graph_builder_apply.go b/internal/terraform/graph_builder_apply.go deleted file mode 100644 index 29e60ff6a0d8..000000000000 --- a/internal/terraform/graph_builder_apply.go +++ /dev/null @@ -1,175 +0,0 @@ -package terraform - -import ( - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/dag" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -// ApplyGraphBuilder implements GraphBuilder and is responsible for building -// a graph for applying a Terraform diff. -// -// Because the graph is built from the diff (vs. the config or state), -// this helps ensure that the apply-time graph doesn't modify any resources -// that aren't explicitly in the diff. There are other scenarios where the -// diff can be deviated, so this is just one layer of protection. -type ApplyGraphBuilder struct { - // Config is the configuration tree that the diff was built from. - Config *configs.Config - - // Changes describes the changes that we need apply. - Changes *plans.Changes - - // State is the current state - State *states.State - - // RootVariableValues are the root module input variables captured as - // part of the plan object, which we must reproduce in the apply step - // to get a consistent result. - RootVariableValues InputValues - - // Plugins is a library of the plug-in components (providers and - // provisioners) available for use. - Plugins *contextPlugins - - // Targets are resources to target. This is only required to make sure - // unnecessary outputs aren't included in the apply graph. The plan - // builder successfully handles targeting resources. In the future, - // outputs should go into the diff so that this is unnecessary. - Targets []addrs.Targetable - - // ForceReplace are the resource instance addresses that the user - // requested to force replacement for when creating the plan, if any. - // The apply step refers to these as part of verifying that the planned - // actions remain consistent between plan and apply. - ForceReplace []addrs.AbsResourceInstance - - // Plan Operation this graph will be used for. - Operation walkOperation -} - -// See GraphBuilder -func (b *ApplyGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics) { - return (&BasicGraphBuilder{ - Steps: b.Steps(), - Name: "ApplyGraphBuilder", - }).Build(path) -} - -// See GraphBuilder -func (b *ApplyGraphBuilder) Steps() []GraphTransformer { - // Custom factory for creating providers. - concreteProvider := func(a *NodeAbstractProvider) dag.Vertex { - return &NodeApplyableProvider{ - NodeAbstractProvider: a, - } - } - - concreteResource := func(a *NodeAbstractResource) dag.Vertex { - return &nodeExpandApplyableResource{ - NodeAbstractResource: a, - } - } - - concreteResourceInstance := func(a *NodeAbstractResourceInstance) dag.Vertex { - return &NodeApplyableResourceInstance{ - NodeAbstractResourceInstance: a, - forceReplace: b.ForceReplace, - } - } - - steps := []GraphTransformer{ - // Creates all the resources represented in the config. During apply, - // we use this just to ensure that the whole-resource metadata is - // updated to reflect things such as whether the count argument is - // set in config, or which provider configuration manages each resource. - &ConfigTransformer{ - Concrete: concreteResource, - Config: b.Config, - }, - - // Add dynamic values - &RootVariableTransformer{Config: b.Config, RawValues: b.RootVariableValues}, - &ModuleVariableTransformer{Config: b.Config}, - &LocalTransformer{Config: b.Config}, - &OutputTransformer{ - Config: b.Config, - ApplyDestroy: b.Operation == walkDestroy, - }, - - // Creates all the resource instances represented in the diff, along - // with dependency edges against the whole-resource nodes added by - // ConfigTransformer above. - &DiffTransformer{ - Concrete: concreteResourceInstance, - State: b.State, - Changes: b.Changes, - Config: b.Config, - }, - - // Attach the state - &AttachStateTransformer{State: b.State}, - - // Create orphan output nodes - &OrphanOutputTransformer{Config: b.Config, State: b.State}, - - // Attach the configuration to any resources - &AttachResourceConfigTransformer{Config: b.Config}, - - // add providers - transformProviders(concreteProvider, b.Config), - - // Remove modules no longer present in the config - &RemovedModuleTransformer{Config: b.Config, State: b.State}, - - // Must attach schemas before ReferenceTransformer so that we can - // analyze the configuration to find references. - &AttachSchemaTransformer{Plugins: b.Plugins, Config: b.Config}, - - // Create expansion nodes for all of the module calls. This must - // come after all other transformers that create nodes representing - // objects that can belong to modules. - &ModuleExpansionTransformer{Config: b.Config}, - - // Connect references so ordering is correct - &ReferenceTransformer{}, - &AttachDependenciesTransformer{}, - - // Detect when create_before_destroy must be forced on for a particular - // node due to dependency edges, to avoid graph cycles during apply. - &ForcedCBDTransformer{}, - - // Destruction ordering - &DestroyEdgeTransformer{ - Changes: b.Changes, - Operation: b.Operation, - }, - &CBDEdgeTransformer{ - Config: b.Config, - State: b.State, - }, - - // We need to remove configuration nodes that are not used at all, as - // they may not be able to evaluate, especially during destroy. - // These include variables, locals, and instance expanders. - &pruneUnusedNodesTransformer{}, - - // Target - &TargetsTransformer{Targets: b.Targets}, - - // Close opened plugin connections - &CloseProviderTransformer{}, - - // close the root module - &CloseRootModuleTransformer{}, - - // Perform the transitive reduction to make our graph a bit - // more understandable if possible (it usually is possible). - &TransitiveReductionTransformer{}, - } - - return steps -} diff --git a/internal/terraform/graph_builder_apply_test.go b/internal/terraform/graph_builder_apply_test.go deleted file mode 100644 index 88ebcfefd1f3..000000000000 --- a/internal/terraform/graph_builder_apply_test.go +++ /dev/null @@ -1,751 +0,0 @@ -package terraform - -import ( - "fmt" - "strings" - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/zclconf/go-cty/cty" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states" -) - -func TestApplyGraphBuilder_impl(t *testing.T) { - var _ GraphBuilder = new(ApplyGraphBuilder) -} - -func TestApplyGraphBuilder(t *testing.T) { - changes := &plans.Changes{ - Resources: []*plans.ResourceInstanceChangeSrc{ - { - Addr: mustResourceInstanceAddr("test_object.create"), - ChangeSrc: plans.ChangeSrc{ - Action: plans.Create, - }, - }, - { - Addr: mustResourceInstanceAddr("test_object.other"), - ChangeSrc: plans.ChangeSrc{ - Action: plans.Update, - }, - }, - { - Addr: mustResourceInstanceAddr("module.child.test_object.create"), - ChangeSrc: plans.ChangeSrc{ - Action: plans.Create, - }, - }, - { - Addr: mustResourceInstanceAddr("module.child.test_object.other"), - ChangeSrc: plans.ChangeSrc{ - Action: plans.Create, - }, - }, - }, - } - - b := &ApplyGraphBuilder{ - Config: testModule(t, "graph-builder-apply-basic"), - Changes: changes, - Plugins: simpleMockPluginLibrary(), - } - - g, err := b.Build(addrs.RootModuleInstance) - if err != nil { - t.Fatalf("err: %s", err) - } - - if g.Path.String() != addrs.RootModuleInstance.String() { - t.Fatalf("wrong path %q", g.Path.String()) - } - - got := strings.TrimSpace(g.String()) - want := strings.TrimSpace(testApplyGraphBuilderStr) - if diff := cmp.Diff(want, got); diff != "" { - t.Fatalf("wrong result\n%s", diff) - } -} - -// This tests the ordering of two resources where a non-CBD depends -// on a CBD. GH-11349. -func TestApplyGraphBuilder_depCbd(t *testing.T) { - changes := &plans.Changes{ - Resources: []*plans.ResourceInstanceChangeSrc{ - { - Addr: mustResourceInstanceAddr("test_object.A"), - ChangeSrc: plans.ChangeSrc{ - Action: plans.CreateThenDelete, - }, - }, - { - Addr: mustResourceInstanceAddr("test_object.B"), - ChangeSrc: plans.ChangeSrc{ - Action: plans.Update, - }, - }, - }, - } - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.A").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"A"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.B").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"B","test_list":["x"]}`), - Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.A")}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - b := &ApplyGraphBuilder{ - Config: testModule(t, "graph-builder-apply-dep-cbd"), - Changes: changes, - Plugins: simpleMockPluginLibrary(), - State: state, - } - - g, err := b.Build(addrs.RootModuleInstance) - if err != nil { - t.Fatalf("err: %s", err) - } - - if g.Path.String() != addrs.RootModuleInstance.String() { - t.Fatalf("wrong path %q", g.Path.String()) - } - - // We're going to go hunting for our deposed instance node here, so we - // can find out its key to use in the assertions below. - var dk states.DeposedKey - for _, v := range g.Vertices() { - tv, ok := v.(*NodeDestroyDeposedResourceInstanceObject) - if !ok { - continue - } - if dk != states.NotDeposed { - t.Fatalf("more than one deposed instance node in the graph; want only one") - } - dk = tv.DeposedKey - } - if dk == states.NotDeposed { - t.Fatalf("no deposed instance node in the graph; want one") - } - - destroyName := fmt.Sprintf("test_object.A (destroy deposed %s)", dk) - - // Create A, Modify B, Destroy A - testGraphHappensBefore( - t, g, - "test_object.A", - destroyName, - ) - testGraphHappensBefore( - t, g, - "test_object.A", - "test_object.B", - ) - testGraphHappensBefore( - t, g, - "test_object.B", - destroyName, - ) -} - -// This tests the ordering of two resources that are both CBD that -// require destroy/create. -func TestApplyGraphBuilder_doubleCBD(t *testing.T) { - changes := &plans.Changes{ - Resources: []*plans.ResourceInstanceChangeSrc{ - { - Addr: mustResourceInstanceAddr("test_object.A"), - ChangeSrc: plans.ChangeSrc{ - Action: plans.CreateThenDelete, - }, - }, - { - Addr: mustResourceInstanceAddr("test_object.B"), - ChangeSrc: plans.ChangeSrc{ - Action: plans.CreateThenDelete, - }, - }, - }, - } - - b := &ApplyGraphBuilder{ - Config: testModule(t, "graph-builder-apply-double-cbd"), - Changes: changes, - Plugins: simpleMockPluginLibrary(), - } - - g, err := b.Build(addrs.RootModuleInstance) - if err != nil { - t.Fatalf("err: %s", err) - } - - if g.Path.String() != addrs.RootModuleInstance.String() { - t.Fatalf("wrong path %q", g.Path.String()) - } - - // We're going to go hunting for our deposed instance node here, so we - // can find out its key to use in the assertions below. - var destroyA, destroyB string - for _, v := range g.Vertices() { - tv, ok := v.(*NodeDestroyDeposedResourceInstanceObject) - if !ok { - continue - } - - switch tv.Addr.Resource.Resource.Name { - case "A": - destroyA = fmt.Sprintf("test_object.A (destroy deposed %s)", tv.DeposedKey) - case "B": - destroyB = fmt.Sprintf("test_object.B (destroy deposed %s)", tv.DeposedKey) - default: - t.Fatalf("unknown instance: %s", tv.Addr) - } - } - - // Create A, Modify B, Destroy A - testGraphHappensBefore( - t, g, - "test_object.A", - destroyA, - ) - testGraphHappensBefore( - t, g, - "test_object.A", - "test_object.B", - ) - testGraphHappensBefore( - t, g, - "test_object.B", - destroyB, - ) -} - -// This tests the ordering of two resources being destroyed that depend -// on each other from only state. GH-11749 -func TestApplyGraphBuilder_destroyStateOnly(t *testing.T) { - changes := &plans.Changes{ - Resources: []*plans.ResourceInstanceChangeSrc{ - { - Addr: mustResourceInstanceAddr("module.child.test_object.A"), - ChangeSrc: plans.ChangeSrc{ - Action: plans.Delete, - }, - }, - { - Addr: mustResourceInstanceAddr("module.child.test_object.B"), - ChangeSrc: plans.ChangeSrc{ - Action: plans.Delete, - }, - }, - }, - } - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey)) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.A").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - child.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.B").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"bar"}`), - Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("module.child.test_object.A")}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - b := &ApplyGraphBuilder{ - Config: testModule(t, "empty"), - Changes: changes, - State: state, - Plugins: simpleMockPluginLibrary(), - } - - g, diags := b.Build(addrs.RootModuleInstance) - if diags.HasErrors() { - t.Fatalf("err: %s", diags.Err()) - } - - if g.Path.String() != addrs.RootModuleInstance.String() { - t.Fatalf("wrong path %q", g.Path.String()) - } - - testGraphHappensBefore( - t, g, - "module.child.test_object.B (destroy)", - "module.child.test_object.A (destroy)") -} - -// This tests the ordering of destroying a single count of a resource. -func TestApplyGraphBuilder_destroyCount(t *testing.T) { - changes := &plans.Changes{ - Resources: []*plans.ResourceInstanceChangeSrc{ - { - Addr: mustResourceInstanceAddr("test_object.A[1]"), - ChangeSrc: plans.ChangeSrc{ - Action: plans.Delete, - }, - }, - { - Addr: mustResourceInstanceAddr("test_object.B"), - ChangeSrc: plans.ChangeSrc{ - Action: plans.Update, - }, - }, - }, - } - - state := states.NewState() - root := state.RootModule() - addrA := mustResourceInstanceAddr("test_object.A[1]") - root.SetResourceInstanceCurrent( - addrA.Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"B"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.B").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"B"}`), - Dependencies: []addrs.ConfigResource{addrA.ContainingResource().Config()}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - b := &ApplyGraphBuilder{ - Config: testModule(t, "graph-builder-apply-count"), - Changes: changes, - Plugins: simpleMockPluginLibrary(), - State: state, - } - - g, err := b.Build(addrs.RootModuleInstance) - if err != nil { - t.Fatalf("err: %s", err) - } - - if g.Path.String() != addrs.RootModuleInstance.String() { - t.Fatalf("wrong module path %q", g.Path) - } - - got := strings.TrimSpace(g.String()) - want := strings.TrimSpace(testApplyGraphBuilderDestroyCountStr) - if diff := cmp.Diff(want, got); diff != "" { - t.Fatalf("wrong result\n%s", diff) - } -} - -func TestApplyGraphBuilder_moduleDestroy(t *testing.T) { - changes := &plans.Changes{ - Resources: []*plans.ResourceInstanceChangeSrc{ - { - Addr: mustResourceInstanceAddr("module.A.test_object.foo"), - ChangeSrc: plans.ChangeSrc{ - Action: plans.Delete, - }, - }, - { - Addr: mustResourceInstanceAddr("module.B.test_object.foo"), - ChangeSrc: plans.ChangeSrc{ - Action: plans.Delete, - }, - }, - }, - } - - state := states.NewState() - modA := state.EnsureModule(addrs.RootModuleInstance.Child("A", addrs.NoKey)) - modA.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - modB := state.EnsureModule(addrs.RootModuleInstance.Child("B", addrs.NoKey)) - modB.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.foo").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo","value":"foo"}`), - Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("module.A.test_object.foo")}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - b := &ApplyGraphBuilder{ - Config: testModule(t, "graph-builder-apply-module-destroy"), - Changes: changes, - Plugins: simpleMockPluginLibrary(), - State: state, - } - - g, err := b.Build(addrs.RootModuleInstance) - if err != nil { - t.Fatalf("err: %s", err) - } - - testGraphHappensBefore( - t, g, - "module.B.test_object.foo (destroy)", - "module.A.test_object.foo (destroy)", - ) -} - -func TestApplyGraphBuilder_targetModule(t *testing.T) { - changes := &plans.Changes{ - Resources: []*plans.ResourceInstanceChangeSrc{ - { - Addr: mustResourceInstanceAddr("test_object.foo"), - ChangeSrc: plans.ChangeSrc{ - Action: plans.Update, - }, - }, - { - Addr: mustResourceInstanceAddr("module.child2.test_object.foo"), - ChangeSrc: plans.ChangeSrc{ - Action: plans.Update, - }, - }, - }, - } - - b := &ApplyGraphBuilder{ - Config: testModule(t, "graph-builder-apply-target-module"), - Changes: changes, - Plugins: simpleMockPluginLibrary(), - Targets: []addrs.Targetable{ - addrs.RootModuleInstance.Child("child2", addrs.NoKey), - }, - } - - g, err := b.Build(addrs.RootModuleInstance) - if err != nil { - t.Fatalf("err: %s", err) - } - - testGraphNotContains(t, g, "module.child1.output.instance_id") -} - -// Ensure that an update resulting from the removal of a resource happens after -// that resource is destroyed. -func TestApplyGraphBuilder_updateFromOrphan(t *testing.T) { - schemas := simpleTestSchemas() - instanceSchema := schemas.Providers[addrs.NewDefaultProvider("test")].ResourceTypes["test_object"] - - bBefore, _ := plans.NewDynamicValue( - cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("b_id"), - "test_string": cty.StringVal("a_id"), - }), instanceSchema.ImpliedType()) - bAfter, _ := plans.NewDynamicValue( - cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("b_id"), - "test_string": cty.StringVal("changed"), - }), instanceSchema.ImpliedType()) - - changes := &plans.Changes{ - Resources: []*plans.ResourceInstanceChangeSrc{ - { - Addr: mustResourceInstanceAddr("test_object.a"), - ChangeSrc: plans.ChangeSrc{ - Action: plans.Delete, - }, - }, - { - Addr: mustResourceInstanceAddr("test_object.b"), - ChangeSrc: plans.ChangeSrc{ - Action: plans.Update, - Before: bBefore, - After: bAfter, - }, - }, - }, - } - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_object", - Name: "a", - }.Instance(addrs.NoKey), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"a_id"}`), - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("test"), - Module: addrs.RootModule, - }, - ) - root.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_object", - Name: "b", - }.Instance(addrs.NoKey), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"b_id","test_string":"a_id"}`), - Dependencies: []addrs.ConfigResource{ - { - Resource: addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_object", - Name: "a", - }, - Module: root.Addr.Module(), - }, - }, - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("test"), - Module: addrs.RootModule, - }, - ) - - b := &ApplyGraphBuilder{ - Config: testModule(t, "graph-builder-apply-orphan-update"), - Changes: changes, - Plugins: simpleMockPluginLibrary(), - State: state, - } - - g, err := b.Build(addrs.RootModuleInstance) - if err != nil { - t.Fatalf("err: %s", err) - } - - expected := strings.TrimSpace(` -test_object.a (destroy) -test_object.b - test_object.a (destroy) -`) - - instanceGraph := filterInstances(g) - got := strings.TrimSpace(instanceGraph.String()) - - if got != expected { - t.Fatalf("expected:\n%s\ngot:\n%s", expected, got) - } -} - -// Ensure that an update resulting from the removal of a resource happens before -// a CBD resource is destroyed. -func TestApplyGraphBuilder_updateFromCBDOrphan(t *testing.T) { - schemas := simpleTestSchemas() - instanceSchema := schemas.Providers[addrs.NewDefaultProvider("test")].ResourceTypes["test_object"] - - bBefore, _ := plans.NewDynamicValue( - cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("b_id"), - "test_string": cty.StringVal("a_id"), - }), instanceSchema.ImpliedType()) - bAfter, _ := plans.NewDynamicValue( - cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("b_id"), - "test_string": cty.StringVal("changed"), - }), instanceSchema.ImpliedType()) - - changes := &plans.Changes{ - Resources: []*plans.ResourceInstanceChangeSrc{ - { - Addr: mustResourceInstanceAddr("test_object.a"), - ChangeSrc: plans.ChangeSrc{ - Action: plans.Delete, - }, - }, - { - Addr: mustResourceInstanceAddr("test_object.b"), - ChangeSrc: plans.ChangeSrc{ - Action: plans.Update, - Before: bBefore, - After: bAfter, - }, - }, - }, - } - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_object", - Name: "a", - }.Instance(addrs.NoKey), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"a_id"}`), - CreateBeforeDestroy: true, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - root.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_object", - Name: "b", - }.Instance(addrs.NoKey), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"b_id","test_string":"a_id"}`), - Dependencies: []addrs.ConfigResource{ - { - Resource: addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_object", - Name: "a", - }, - Module: root.Addr.Module(), - }, - }, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - b := &ApplyGraphBuilder{ - Config: testModule(t, "graph-builder-apply-orphan-update"), - Changes: changes, - Plugins: simpleMockPluginLibrary(), - State: state, - } - - g, err := b.Build(addrs.RootModuleInstance) - if err != nil { - t.Fatalf("err: %s", err) - } - - expected := strings.TrimSpace(` -test_object.a (destroy) - test_object.b -test_object.b -`) - - instanceGraph := filterInstances(g) - got := strings.TrimSpace(instanceGraph.String()) - - if got != expected { - t.Fatalf("expected:\n%s\ngot:\n%s", expected, got) - } -} - -// The orphan clean up node should not be connected to a provider -func TestApplyGraphBuilder_orphanedWithProvider(t *testing.T) { - changes := &plans.Changes{ - Resources: []*plans.ResourceInstanceChangeSrc{ - { - Addr: mustResourceInstanceAddr("test_object.A"), - ChangeSrc: plans.ChangeSrc{ - Action: plans.Delete, - }, - }, - }, - } - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.A").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"A"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"].foo`), - ) - - b := &ApplyGraphBuilder{ - Config: testModule(t, "graph-builder-orphan-alias"), - Changes: changes, - Plugins: simpleMockPluginLibrary(), - State: state, - } - - g, err := b.Build(addrs.RootModuleInstance) - if err != nil { - t.Fatal(err) - } - - // The cleanup node has no state or config of its own, so would create a - // default provider which we don't want. - testGraphNotContains(t, g, "provider.test") -} - -const testApplyGraphBuilderStr = ` -module.child (close) - module.child.test_object.other -module.child (expand) -module.child.test_object.create - module.child.test_object.create (expand) -module.child.test_object.create (expand) - module.child (expand) - provider["registry.terraform.io/hashicorp/test"] -module.child.test_object.other - module.child.test_object.create - module.child.test_object.other (expand) -module.child.test_object.other (expand) - module.child (expand) - provider["registry.terraform.io/hashicorp/test"] -provider["registry.terraform.io/hashicorp/test"] -provider["registry.terraform.io/hashicorp/test"] (close) - module.child.test_object.other - test_object.other -root - module.child (close) - provider["registry.terraform.io/hashicorp/test"] (close) -test_object.create - test_object.create (expand) -test_object.create (expand) - provider["registry.terraform.io/hashicorp/test"] -test_object.other - test_object.create - test_object.other (expand) -test_object.other (expand) - provider["registry.terraform.io/hashicorp/test"] -` - -const testApplyGraphBuilderDestroyCountStr = ` -provider["registry.terraform.io/hashicorp/test"] -provider["registry.terraform.io/hashicorp/test"] (close) - test_object.B -root - provider["registry.terraform.io/hashicorp/test"] (close) -test_object.A (expand) - provider["registry.terraform.io/hashicorp/test"] -test_object.A[1] (destroy) - provider["registry.terraform.io/hashicorp/test"] -test_object.B - test_object.A (expand) - test_object.A[1] (destroy) - test_object.B (expand) -test_object.B (expand) - provider["registry.terraform.io/hashicorp/test"] -` diff --git a/internal/terraform/graph_builder_eval.go b/internal/terraform/graph_builder_eval.go deleted file mode 100644 index cb3606d62c9f..000000000000 --- a/internal/terraform/graph_builder_eval.go +++ /dev/null @@ -1,108 +0,0 @@ -package terraform - -import ( - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/dag" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -// EvalGraphBuilder implements GraphBuilder and constructs a graph suitable -// for evaluating in-memory values (input variables, local values, output -// values) in the state without any other side-effects. -// -// This graph is used only in weird cases, such as the "terraform console" -// CLI command, where we need to evaluate expressions against the state -// without taking any other actions. -// -// The generated graph will include nodes for providers, resources, etc -// just to allow indirect dependencies to be resolved, but these nodes will -// not take any actions themselves since we assume that their parts of the -// state, if any, are already complete. -// -// Although the providers are never configured, they must still be available -// in order to obtain schema information used for type checking, etc. -type EvalGraphBuilder struct { - // Config is the configuration tree. - Config *configs.Config - - // State is the current state - State *states.State - - // RootVariableValues are the raw input values for root input variables - // given by the caller, which we'll resolve into final values as part - // of the plan walk. - RootVariableValues InputValues - - // Plugins is a library of plug-in components (providers and - // provisioners) available for use. - Plugins *contextPlugins -} - -// See GraphBuilder -func (b *EvalGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics) { - return (&BasicGraphBuilder{ - Steps: b.Steps(), - Name: "EvalGraphBuilder", - }).Build(path) -} - -// See GraphBuilder -func (b *EvalGraphBuilder) Steps() []GraphTransformer { - concreteProvider := func(a *NodeAbstractProvider) dag.Vertex { - return &NodeEvalableProvider{ - NodeAbstractProvider: a, - } - } - - steps := []GraphTransformer{ - // Creates all the data resources that aren't in the state. This will also - // add any orphans from scaling in as destroy nodes. - &ConfigTransformer{ - Config: b.Config, - }, - - // Add dynamic values - &RootVariableTransformer{Config: b.Config, RawValues: b.RootVariableValues}, - &ModuleVariableTransformer{Config: b.Config}, - &LocalTransformer{Config: b.Config}, - &OutputTransformer{ - Config: b.Config, - Planning: true, - }, - - // Attach the configuration to any resources - &AttachResourceConfigTransformer{Config: b.Config}, - - // Attach the state - &AttachStateTransformer{State: b.State}, - - transformProviders(concreteProvider, b.Config), - - // Must attach schemas before ReferenceTransformer so that we can - // analyze the configuration to find references. - &AttachSchemaTransformer{Plugins: b.Plugins, Config: b.Config}, - - // Create expansion nodes for all of the module calls. This must - // come after all other transformers that create nodes representing - // objects that can belong to modules. - &ModuleExpansionTransformer{Config: b.Config}, - - // Connect so that the references are ready for targeting. We'll - // have to connect again later for providers and so on. - &ReferenceTransformer{}, - - // Although we don't configure providers, we do still start them up - // to get their schemas, and so we must shut them down again here. - &CloseProviderTransformer{}, - - // Close root module - &CloseRootModuleTransformer{}, - - // Remove redundant edges to simplify the graph. - &TransitiveReductionTransformer{}, - } - - return steps -} diff --git a/internal/terraform/graph_builder_plan.go b/internal/terraform/graph_builder_plan.go deleted file mode 100644 index f085e9aa2dad..000000000000 --- a/internal/terraform/graph_builder_plan.go +++ /dev/null @@ -1,305 +0,0 @@ -package terraform - -import ( - "log" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/dag" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -// PlanGraphBuilder is a GraphBuilder implementation that builds a graph for -// planning and for other "plan-like" operations which don't require an -// already-calculated plan as input. -// -// Unlike the apply graph builder, this graph builder: -// -// - Makes its decisions primarily based on the given configuration, which -// represents the desired state. -// -// - Ignores certain lifecycle concerns like create_before_destroy, because -// those are only important once we already know what action we're planning -// to take against a particular resource instance. -type PlanGraphBuilder struct { - // Config is the configuration tree to build a plan from. - Config *configs.Config - - // State is the current state - State *states.State - - // RootVariableValues are the raw input values for root input variables - // given by the caller, which we'll resolve into final values as part - // of the plan walk. - RootVariableValues InputValues - - // Plugins is a library of plug-in components (providers and - // provisioners) available for use. - Plugins *contextPlugins - - // Targets are resources to target - Targets []addrs.Targetable - - // ForceReplace are resource instances where if we would normally have - // generated a NoOp or Update action then we'll force generating a replace - // action instead. Create and Delete actions are not affected. - ForceReplace []addrs.AbsResourceInstance - - // skipRefresh indicates that we should skip refreshing managed resources - skipRefresh bool - - // preDestroyRefresh indicates that we are executing the refresh which - // happens immediately before a destroy plan, which happens to use the - // normal planing mode so skipPlanChanges cannot be set. - preDestroyRefresh bool - - // skipPlanChanges indicates that we should skip the step of comparing - // prior state with configuration and generating planned changes to - // resource instances. (This is for the "refresh only" planning mode, - // where we _only_ do the refresh step.) - skipPlanChanges bool - - ConcreteProvider ConcreteProviderNodeFunc - ConcreteResource ConcreteResourceNodeFunc - ConcreteResourceInstance ConcreteResourceInstanceNodeFunc - ConcreteResourceOrphan ConcreteResourceInstanceNodeFunc - ConcreteResourceInstanceDeposed ConcreteResourceInstanceDeposedNodeFunc - ConcreteModule ConcreteModuleNodeFunc - - // Plan Operation this graph will be used for. - Operation walkOperation - - // ImportTargets are the list of resources to import. - ImportTargets []*ImportTarget -} - -// See GraphBuilder -func (b *PlanGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics) { - log.Printf("[TRACE] building graph for %s", b.Operation) - return (&BasicGraphBuilder{ - Steps: b.Steps(), - Name: "PlanGraphBuilder", - }).Build(path) -} - -// See GraphBuilder -func (b *PlanGraphBuilder) Steps() []GraphTransformer { - switch b.Operation { - case walkPlan: - b.initPlan() - case walkPlanDestroy: - b.initDestroy() - case walkValidate: - b.initValidate() - case walkImport: - b.initImport() - default: - panic("invalid plan operation: " + b.Operation.String()) - } - - steps := []GraphTransformer{ - // Creates all the resources represented in the config - &ConfigTransformer{ - Concrete: b.ConcreteResource, - Config: b.Config, - - // Resources are not added from the config on destroy. - skip: b.Operation == walkPlanDestroy, - - importTargets: b.ImportTargets, - }, - - // Add dynamic values - &RootVariableTransformer{Config: b.Config, RawValues: b.RootVariableValues}, - &ModuleVariableTransformer{Config: b.Config}, - &LocalTransformer{Config: b.Config}, - &OutputTransformer{ - Config: b.Config, - RefreshOnly: b.skipPlanChanges || b.preDestroyRefresh, - PlanDestroy: b.Operation == walkPlanDestroy, - - // NOTE: We currently treat anything built with the plan graph - // builder as "planning" for our purposes here, because we share - // the same graph node implementation between all of the walk - // types and so the pre-planning walks still think they are - // producing a plan even though we immediately discard it. - Planning: true, - }, - - // Add orphan resources - &OrphanResourceInstanceTransformer{ - Concrete: b.ConcreteResourceOrphan, - State: b.State, - Config: b.Config, - skip: b.Operation == walkPlanDestroy, - }, - - // We also need nodes for any deposed instance objects present in the - // state, so we can plan to destroy them. (During plan this will - // intentionally skip creating nodes for _current_ objects, since - // ConfigTransformer created nodes that will do that during - // DynamicExpand.) - &StateTransformer{ - ConcreteCurrent: b.ConcreteResourceInstance, - ConcreteDeposed: b.ConcreteResourceInstanceDeposed, - State: b.State, - }, - - // Attach the state - &AttachStateTransformer{State: b.State}, - - // Create orphan output nodes - &OrphanOutputTransformer{ - Config: b.Config, - State: b.State, - Planning: true, - }, - - // Attach the configuration to any resources - &AttachResourceConfigTransformer{Config: b.Config}, - - // add providers - transformProviders(b.ConcreteProvider, b.Config), - - // Remove modules no longer present in the config - &RemovedModuleTransformer{Config: b.Config, State: b.State}, - - // Must attach schemas before ReferenceTransformer so that we can - // analyze the configuration to find references. - &AttachSchemaTransformer{Plugins: b.Plugins, Config: b.Config}, - - // Create expansion nodes for all of the module calls. This must - // come after all other transformers that create nodes representing - // objects that can belong to modules. - &ModuleExpansionTransformer{Concrete: b.ConcreteModule, Config: b.Config}, - - &ReferenceTransformer{}, - - &AttachDependenciesTransformer{}, - - // Make sure data sources are aware of any depends_on from the - // configuration - &attachDataResourceDependsOnTransformer{}, - - // DestroyEdgeTransformer is only required during a plan so that the - // TargetsTransformer can determine which nodes to keep in the graph. - &DestroyEdgeTransformer{}, - - &pruneUnusedNodesTransformer{ - skip: b.Operation != walkPlanDestroy, - }, - - // Target - &TargetsTransformer{Targets: b.Targets}, - - // Detect when create_before_destroy must be forced on for a particular - // node due to dependency edges, to avoid graph cycles during apply. - &ForcedCBDTransformer{}, - - // Close opened plugin connections - &CloseProviderTransformer{}, - - // Close the root module - &CloseRootModuleTransformer{}, - - // Perform the transitive reduction to make our graph a bit - // more understandable if possible (it usually is possible). - &TransitiveReductionTransformer{}, - } - - return steps -} - -func (b *PlanGraphBuilder) initPlan() { - b.ConcreteProvider = func(a *NodeAbstractProvider) dag.Vertex { - return &NodeApplyableProvider{ - NodeAbstractProvider: a, - } - } - - b.ConcreteResource = func(a *NodeAbstractResource) dag.Vertex { - return &nodeExpandPlannableResource{ - NodeAbstractResource: a, - skipRefresh: b.skipRefresh, - skipPlanChanges: b.skipPlanChanges, - preDestroyRefresh: b.preDestroyRefresh, - forceReplace: b.ForceReplace, - } - } - - b.ConcreteResourceOrphan = func(a *NodeAbstractResourceInstance) dag.Vertex { - return &NodePlannableResourceInstanceOrphan{ - NodeAbstractResourceInstance: a, - skipRefresh: b.skipRefresh, - skipPlanChanges: b.skipPlanChanges, - } - } - - b.ConcreteResourceInstanceDeposed = func(a *NodeAbstractResourceInstance, key states.DeposedKey) dag.Vertex { - return &NodePlanDeposedResourceInstanceObject{ - NodeAbstractResourceInstance: a, - DeposedKey: key, - - skipRefresh: b.skipRefresh, - skipPlanChanges: b.skipPlanChanges, - } - } -} - -func (b *PlanGraphBuilder) initDestroy() { - b.initPlan() - - b.ConcreteResourceInstance = func(a *NodeAbstractResourceInstance) dag.Vertex { - return &NodePlanDestroyableResourceInstance{ - NodeAbstractResourceInstance: a, - skipRefresh: b.skipRefresh, - } - } -} - -func (b *PlanGraphBuilder) initValidate() { - // Set the provider to the normal provider. This will ask for input. - b.ConcreteProvider = func(a *NodeAbstractProvider) dag.Vertex { - return &NodeApplyableProvider{ - NodeAbstractProvider: a, - } - } - - b.ConcreteResource = func(a *NodeAbstractResource) dag.Vertex { - return &NodeValidatableResource{ - NodeAbstractResource: a, - } - } - - b.ConcreteModule = func(n *nodeExpandModule) dag.Vertex { - return &nodeValidateModule{ - nodeExpandModule: *n, - } - } -} - -func (b *PlanGraphBuilder) initImport() { - b.ConcreteProvider = func(a *NodeAbstractProvider) dag.Vertex { - return &NodeApplyableProvider{ - NodeAbstractProvider: a, - } - } - - b.ConcreteResource = func(a *NodeAbstractResource) dag.Vertex { - return &nodeExpandPlannableResource{ - NodeAbstractResource: a, - - // For now we always skip planning changes for import, since we are - // not going to combine importing with other changes. This is - // temporary to try and maintain existing import behaviors, but - // planning will need to be allowed for more complex configurations. - skipPlanChanges: true, - - // We also skip refresh for now, since the plan output is written - // as the new state, and users are not expecting the import process - // to update any other instances in state. - skipRefresh: true, - } - } -} diff --git a/internal/terraform/graph_builder_plan_test.go b/internal/terraform/graph_builder_plan_test.go deleted file mode 100644 index 8775e1f17518..000000000000 --- a/internal/terraform/graph_builder_plan_test.go +++ /dev/null @@ -1,273 +0,0 @@ -package terraform - -import ( - "strings" - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/zclconf/go-cty/cty" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/providers" -) - -func TestPlanGraphBuilder_impl(t *testing.T) { - var _ GraphBuilder = new(PlanGraphBuilder) -} - -func TestPlanGraphBuilder(t *testing.T) { - awsProvider := &MockProvider{ - GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{ - Provider: providers.Schema{Block: simpleTestSchema()}, - ResourceTypes: map[string]providers.Schema{ - "aws_security_group": {Block: simpleTestSchema()}, - "aws_instance": {Block: simpleTestSchema()}, - "aws_load_balancer": {Block: simpleTestSchema()}, - }, - }, - } - openstackProvider := mockProviderWithResourceTypeSchema("openstack_floating_ip", simpleTestSchema()) - plugins := newContextPlugins(map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): providers.FactoryFixed(awsProvider), - addrs.NewDefaultProvider("openstack"): providers.FactoryFixed(openstackProvider), - }, nil) - - b := &PlanGraphBuilder{ - Config: testModule(t, "graph-builder-plan-basic"), - Plugins: plugins, - Operation: walkPlan, - } - - g, err := b.Build(addrs.RootModuleInstance) - if err != nil { - t.Fatalf("err: %s", err) - } - - if g.Path.String() != addrs.RootModuleInstance.String() { - t.Fatalf("wrong module path %q", g.Path) - } - - got := strings.TrimSpace(g.String()) - want := strings.TrimSpace(testPlanGraphBuilderStr) - if diff := cmp.Diff(want, got); diff != "" { - t.Fatalf("wrong result\n%s", diff) - } -} - -func TestPlanGraphBuilder_dynamicBlock(t *testing.T) { - provider := mockProviderWithResourceTypeSchema("test_thing", &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Computed: true}, - "list": {Type: cty.List(cty.String), Computed: true}, - }, - BlockTypes: map[string]*configschema.NestedBlock{ - "nested": { - Nesting: configschema.NestingList, - Block: configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": {Type: cty.String, Optional: true}, - }, - }, - }, - }, - }) - plugins := newContextPlugins(map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): providers.FactoryFixed(provider), - }, nil) - - b := &PlanGraphBuilder{ - Config: testModule(t, "graph-builder-plan-dynblock"), - Plugins: plugins, - Operation: walkPlan, - } - - g, err := b.Build(addrs.RootModuleInstance) - if err != nil { - t.Fatalf("err: %s", err) - } - - if g.Path.String() != addrs.RootModuleInstance.String() { - t.Fatalf("wrong module path %q", g.Path) - } - - // This test is here to make sure we properly detect references inside - // the special "dynamic" block construct. The most important thing here - // is that at the end test_thing.c depends on both test_thing.a and - // test_thing.b. Other details might shift over time as other logic in - // the graph builders changes. - got := strings.TrimSpace(g.String()) - want := strings.TrimSpace(` -provider["registry.terraform.io/hashicorp/test"] -provider["registry.terraform.io/hashicorp/test"] (close) - test_thing.c (expand) -root - provider["registry.terraform.io/hashicorp/test"] (close) -test_thing.a (expand) - provider["registry.terraform.io/hashicorp/test"] -test_thing.b (expand) - provider["registry.terraform.io/hashicorp/test"] -test_thing.c (expand) - test_thing.a (expand) - test_thing.b (expand) -`) - if diff := cmp.Diff(want, got); diff != "" { - t.Fatalf("wrong result\n%s", diff) - } -} - -func TestPlanGraphBuilder_attrAsBlocks(t *testing.T) { - provider := mockProviderWithResourceTypeSchema("test_thing", &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "id": {Type: cty.String, Computed: true}, - "nested": { - Type: cty.List(cty.Object(map[string]cty.Type{ - "foo": cty.String, - })), - Optional: true, - }, - }, - }) - plugins := newContextPlugins(map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("test"): providers.FactoryFixed(provider), - }, nil) - - b := &PlanGraphBuilder{ - Config: testModule(t, "graph-builder-plan-attr-as-blocks"), - Plugins: plugins, - Operation: walkPlan, - } - - g, err := b.Build(addrs.RootModuleInstance) - if err != nil { - t.Fatalf("err: %s", err) - } - - if g.Path.String() != addrs.RootModuleInstance.String() { - t.Fatalf("wrong module path %q", g.Path) - } - - // This test is here to make sure we properly detect references inside - // the "nested" block that is actually defined in the schema as a - // list-of-objects attribute. This requires some special effort - // inside lang.ReferencesInBlock to make sure it searches blocks of - // type "nested" along with an attribute named "nested". - got := strings.TrimSpace(g.String()) - want := strings.TrimSpace(` -provider["registry.terraform.io/hashicorp/test"] -provider["registry.terraform.io/hashicorp/test"] (close) - test_thing.b (expand) -root - provider["registry.terraform.io/hashicorp/test"] (close) -test_thing.a (expand) - provider["registry.terraform.io/hashicorp/test"] -test_thing.b (expand) - test_thing.a (expand) -`) - if diff := cmp.Diff(want, got); diff != "" { - t.Fatalf("wrong result\n%s", diff) - } -} - -func TestPlanGraphBuilder_targetModule(t *testing.T) { - b := &PlanGraphBuilder{ - Config: testModule(t, "graph-builder-plan-target-module-provider"), - Plugins: simpleMockPluginLibrary(), - Targets: []addrs.Targetable{ - addrs.RootModuleInstance.Child("child2", addrs.NoKey), - }, - Operation: walkPlan, - } - - g, err := b.Build(addrs.RootModuleInstance) - if err != nil { - t.Fatalf("err: %s", err) - } - - t.Logf("Graph: %s", g.String()) - - testGraphNotContains(t, g, `module.child1.provider["registry.terraform.io/hashicorp/test"]`) - testGraphNotContains(t, g, "module.child1.test_object.foo") -} - -func TestPlanGraphBuilder_forEach(t *testing.T) { - awsProvider := mockProviderWithResourceTypeSchema("aws_instance", simpleTestSchema()) - - plugins := newContextPlugins(map[addrs.Provider]providers.Factory{ - addrs.NewDefaultProvider("aws"): providers.FactoryFixed(awsProvider), - }, nil) - - b := &PlanGraphBuilder{ - Config: testModule(t, "plan-for-each"), - Plugins: plugins, - Operation: walkPlan, - } - - g, err := b.Build(addrs.RootModuleInstance) - if err != nil { - t.Fatalf("err: %s", err) - } - - if g.Path.String() != addrs.RootModuleInstance.String() { - t.Fatalf("wrong module path %q", g.Path) - } - - got := strings.TrimSpace(g.String()) - // We're especially looking for the edge here, where aws_instance.bat - // has a dependency on aws_instance.boo - want := strings.TrimSpace(testPlanGraphBuilderForEachStr) - if diff := cmp.Diff(want, got); diff != "" { - t.Fatalf("wrong result\n%s", diff) - } -} - -const testPlanGraphBuilderStr = ` -aws_instance.web (expand) - aws_security_group.firewall (expand) - var.foo -aws_load_balancer.weblb (expand) - aws_instance.web (expand) -aws_security_group.firewall (expand) - provider["registry.terraform.io/hashicorp/aws"] -local.instance_id (expand) - aws_instance.web (expand) -openstack_floating_ip.random (expand) - provider["registry.terraform.io/hashicorp/openstack"] -output.instance_id (expand) - local.instance_id (expand) -provider["registry.terraform.io/hashicorp/aws"] - openstack_floating_ip.random (expand) -provider["registry.terraform.io/hashicorp/aws"] (close) - aws_load_balancer.weblb (expand) -provider["registry.terraform.io/hashicorp/openstack"] -provider["registry.terraform.io/hashicorp/openstack"] (close) - openstack_floating_ip.random (expand) -root - output.instance_id (expand) - provider["registry.terraform.io/hashicorp/aws"] (close) - provider["registry.terraform.io/hashicorp/openstack"] (close) -var.foo -` -const testPlanGraphBuilderForEachStr = ` -aws_instance.bar (expand) - provider["registry.terraform.io/hashicorp/aws"] -aws_instance.bar2 (expand) - provider["registry.terraform.io/hashicorp/aws"] -aws_instance.bat (expand) - aws_instance.boo (expand) -aws_instance.baz (expand) - provider["registry.terraform.io/hashicorp/aws"] -aws_instance.boo (expand) - provider["registry.terraform.io/hashicorp/aws"] -aws_instance.foo (expand) - provider["registry.terraform.io/hashicorp/aws"] -provider["registry.terraform.io/hashicorp/aws"] -provider["registry.terraform.io/hashicorp/aws"] (close) - aws_instance.bar (expand) - aws_instance.bar2 (expand) - aws_instance.bat (expand) - aws_instance.baz (expand) - aws_instance.foo (expand) -root - provider["registry.terraform.io/hashicorp/aws"] (close) -` diff --git a/internal/terraform/graph_builder_test.go b/internal/terraform/graph_builder_test.go deleted file mode 100644 index 414fc0b8d766..000000000000 --- a/internal/terraform/graph_builder_test.go +++ /dev/null @@ -1,64 +0,0 @@ -package terraform - -import ( - "strings" - "testing" - - "github.com/hashicorp/terraform/internal/addrs" - - "github.com/hashicorp/terraform/internal/dag" -) - -func TestBasicGraphBuilder_impl(t *testing.T) { - var _ GraphBuilder = new(BasicGraphBuilder) -} - -func TestBasicGraphBuilder(t *testing.T) { - b := &BasicGraphBuilder{ - Steps: []GraphTransformer{ - &testBasicGraphBuilderTransform{1}, - }, - } - - g, err := b.Build(addrs.RootModuleInstance) - if err != nil { - t.Fatalf("err: %s", err) - } - - if g.Path.String() != addrs.RootModuleInstance.String() { - t.Fatalf("wrong module path %q", g.Path) - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(testBasicGraphBuilderStr) - if actual != expected { - t.Fatalf("bad: %s", actual) - } -} - -func TestBasicGraphBuilder_validate(t *testing.T) { - b := &BasicGraphBuilder{ - Steps: []GraphTransformer{ - &testBasicGraphBuilderTransform{1}, - &testBasicGraphBuilderTransform{2}, - }, - } - - _, err := b.Build(addrs.RootModuleInstance) - if err == nil { - t.Fatal("should error") - } -} - -type testBasicGraphBuilderTransform struct { - V dag.Vertex -} - -func (t *testBasicGraphBuilderTransform) Transform(g *Graph) error { - g.Add(t.V) - return nil -} - -const testBasicGraphBuilderStr = ` -1 -` diff --git a/internal/terraform/graph_dot.go b/internal/terraform/graph_dot.go deleted file mode 100644 index 22e701bcc122..000000000000 --- a/internal/terraform/graph_dot.go +++ /dev/null @@ -1,9 +0,0 @@ -package terraform - -import "github.com/hashicorp/terraform/internal/dag" - -// GraphDot returns the dot formatting of a visual representation of -// the given Terraform graph. -func GraphDot(g *Graph, opts *dag.DotOpts) (string, error) { - return string(g.Dot(opts)), nil -} diff --git a/internal/terraform/graph_dot_test.go b/internal/terraform/graph_dot_test.go deleted file mode 100644 index 5042534b4ea2..000000000000 --- a/internal/terraform/graph_dot_test.go +++ /dev/null @@ -1,313 +0,0 @@ -package terraform - -import ( - "strings" - "testing" - - "github.com/hashicorp/terraform/internal/dag" -) - -func TestGraphDot(t *testing.T) { - cases := []struct { - Name string - Graph testGraphFunc - Opts dag.DotOpts - Expect string - Error string - }{ - { - Name: "empty", - Graph: func() *Graph { return &Graph{} }, - Expect: ` -digraph { - compound = "true" - newrank = "true" - subgraph "root" { - } -}`, - }, - { - Name: "three-level", - Graph: func() *Graph { - var g Graph - root := &testDrawableOrigin{"root"} - g.Add(root) - - levelOne := []interface{}{"foo", "bar"} - for i, s := range levelOne { - levelOne[i] = &testDrawable{ - VertexName: s.(string), - } - v := levelOne[i] - - g.Add(v) - g.Connect(dag.BasicEdge(v, root)) - } - - levelTwo := []string{"baz", "qux"} - for i, s := range levelTwo { - v := &testDrawable{ - VertexName: s, - } - - g.Add(v) - g.Connect(dag.BasicEdge(v, levelOne[i])) - } - - return &g - }, - Expect: ` -digraph { - compound = "true" - newrank = "true" - subgraph "root" { - "[root] bar" - "[root] baz" - "[root] foo" - "[root] qux" - "[root] root" - "[root] bar" -> "[root] root" - "[root] baz" -> "[root] foo" - "[root] foo" -> "[root] root" - "[root] qux" -> "[root] bar" - } -} - `, - }, - - { - Name: "cycle", - Opts: dag.DotOpts{ - DrawCycles: true, - }, - Graph: func() *Graph { - var g Graph - root := &testDrawableOrigin{"root"} - g.Add(root) - - vA := g.Add(&testDrawable{ - VertexName: "A", - }) - - vB := g.Add(&testDrawable{ - VertexName: "B", - }) - - vC := g.Add(&testDrawable{ - VertexName: "C", - }) - - g.Connect(dag.BasicEdge(vA, root)) - g.Connect(dag.BasicEdge(vA, vC)) - g.Connect(dag.BasicEdge(vB, vA)) - g.Connect(dag.BasicEdge(vC, vB)) - - return &g - }, - Expect: ` -digraph { - compound = "true" - newrank = "true" - subgraph "root" { - "[root] A" - "[root] B" - "[root] C" - "[root] root" - "[root] A" -> "[root] B" [color = "red", penwidth = "2.0"] - "[root] A" -> "[root] C" - "[root] A" -> "[root] root" - "[root] B" -> "[root] A" - "[root] B" -> "[root] C" [color = "red", penwidth = "2.0"] - "[root] C" -> "[root] A" [color = "red", penwidth = "2.0"] - "[root] C" -> "[root] B" - } -} - `, - }, - - { - Name: "subgraphs, no depth restriction", - Opts: dag.DotOpts{ - MaxDepth: -1, - }, - Graph: func() *Graph { - var g Graph - root := &testDrawableOrigin{"root"} - g.Add(root) - - var sub Graph - vSubRoot := sub.Add(&testDrawableOrigin{"sub_root"}) - - var subsub Graph - subsub.Add(&testDrawableOrigin{"subsub_root"}) - vSubV := sub.Add(&testDrawableSubgraph{ - VertexName: "subsub", - SubgraphMock: &subsub, - }) - - vSub := g.Add(&testDrawableSubgraph{ - VertexName: "sub", - SubgraphMock: &sub, - }) - - g.Connect(dag.BasicEdge(vSub, root)) - sub.Connect(dag.BasicEdge(vSubV, vSubRoot)) - - return &g - }, - Expect: ` -digraph { - compound = "true" - newrank = "true" - subgraph "root" { - "[root] root" - "[root] sub" - "[root] sub" -> "[root] root" - } - subgraph "cluster_sub" { - label = "sub" - "[sub] sub_root" - "[sub] subsub" - "[sub] subsub" -> "[sub] sub_root" - } - subgraph "cluster_subsub" { - label = "subsub" - "[subsub] subsub_root" - } -} - `, - }, - - { - Name: "subgraphs, with depth restriction", - Opts: dag.DotOpts{ - MaxDepth: 1, - }, - Graph: func() *Graph { - var g Graph - root := &testDrawableOrigin{"root"} - g.Add(root) - - var sub Graph - rootSub := sub.Add(&testDrawableOrigin{"sub_root"}) - - var subsub Graph - subsub.Add(&testDrawableOrigin{"subsub_root"}) - - subV := sub.Add(&testDrawableSubgraph{ - VertexName: "subsub", - SubgraphMock: &subsub, - }) - vSub := g.Add(&testDrawableSubgraph{ - VertexName: "sub", - SubgraphMock: &sub, - }) - - g.Connect(dag.BasicEdge(vSub, root)) - sub.Connect(dag.BasicEdge(subV, rootSub)) - return &g - }, - Expect: ` -digraph { - compound = "true" - newrank = "true" - subgraph "root" { - "[root] root" - "[root] sub" - "[root] sub" -> "[root] root" - } - subgraph "cluster_sub" { - label = "sub" - "[sub] sub_root" - "[sub] subsub" - "[sub] subsub" -> "[sub] sub_root" - } -} - `, - }, - } - - for _, tc := range cases { - tn := tc.Name - t.Run(tn, func(t *testing.T) { - g := tc.Graph() - var err error - //actual, err := GraphDot(g, &tc.Opts) - actual := string(g.Dot(&tc.Opts)) - - if err == nil && tc.Error != "" { - t.Fatalf("%s: expected err: %s, got none", tn, tc.Error) - } - if err != nil && tc.Error == "" { - t.Fatalf("%s: unexpected err: %s", tn, err) - } - if err != nil && tc.Error != "" { - if !strings.Contains(err.Error(), tc.Error) { - t.Fatalf("%s: expected err: %s\nto contain: %s", tn, err, tc.Error) - } - return - } - - expected := strings.TrimSpace(tc.Expect) + "\n" - if actual != expected { - t.Fatalf("%s:\n\nexpected:\n%s\n\ngot:\n%s", tn, expected, actual) - } - }) - } -} - -type testGraphFunc func() *Graph - -type testDrawable struct { - VertexName string - DependentOnMock []string -} - -func (node *testDrawable) Name() string { - return node.VertexName -} -func (node *testDrawable) DotNode(n string, opts *dag.DotOpts) *dag.DotNode { - return &dag.DotNode{Name: n, Attrs: map[string]string{}} -} -func (node *testDrawable) DependableName() []string { - return []string{node.VertexName} -} -func (node *testDrawable) DependentOn() []string { - return node.DependentOnMock -} - -type testDrawableOrigin struct { - VertexName string -} - -func (node *testDrawableOrigin) Name() string { - return node.VertexName -} -func (node *testDrawableOrigin) DotNode(n string, opts *dag.DotOpts) *dag.DotNode { - return &dag.DotNode{Name: n, Attrs: map[string]string{}} -} -func (node *testDrawableOrigin) DotOrigin() bool { - return true -} -func (node *testDrawableOrigin) DependableName() []string { - return []string{node.VertexName} -} - -type testDrawableSubgraph struct { - VertexName string - SubgraphMock *Graph - DependentOnMock []string -} - -func (node *testDrawableSubgraph) Name() string { - return node.VertexName -} -func (node *testDrawableSubgraph) Subgraph() dag.Grapher { - return node.SubgraphMock -} -func (node *testDrawableSubgraph) DotNode(n string, opts *dag.DotOpts) *dag.DotNode { - return &dag.DotNode{Name: n, Attrs: map[string]string{}} -} -func (node *testDrawableSubgraph) DependentOn() []string { - return node.DependentOnMock -} diff --git a/internal/terraform/graph_interface_subgraph.go b/internal/terraform/graph_interface_subgraph.go deleted file mode 100644 index 6aa2206dfd74..000000000000 --- a/internal/terraform/graph_interface_subgraph.go +++ /dev/null @@ -1,17 +0,0 @@ -package terraform - -import ( - "github.com/hashicorp/terraform/internal/addrs" -) - -// GraphNodeModuleInstance says that a node is part of a graph with a -// different path, and the context should be adjusted accordingly. -type GraphNodeModuleInstance interface { - Path() addrs.ModuleInstance -} - -// GraphNodeModulePath is implemented by all referenceable nodes, to indicate -// their configuration path in unexpanded modules. -type GraphNodeModulePath interface { - ModulePath() addrs.Module -} diff --git a/internal/terraform/graph_test.go b/internal/terraform/graph_test.go deleted file mode 100644 index 5e163a021353..000000000000 --- a/internal/terraform/graph_test.go +++ /dev/null @@ -1,56 +0,0 @@ -package terraform - -import ( - "testing" - - "github.com/hashicorp/terraform/internal/dag" -) - -// testGraphnotContains is an assertion helper that tests that a node is -// NOT contained in the graph. -func testGraphNotContains(t *testing.T, g *Graph, name string) { - for _, v := range g.Vertices() { - if dag.VertexName(v) == name { - t.Fatalf( - "Expected %q to NOT be in:\n\n%s", - name, g.String()) - } - } -} - -// testGraphHappensBefore is an assertion helper that tests that node -// A (dag.VertexName value) happens before node B. -func testGraphHappensBefore(t *testing.T, g *Graph, A, B string) { - t.Helper() - // Find the B vertex - var vertexB dag.Vertex - for _, v := range g.Vertices() { - if dag.VertexName(v) == B { - vertexB = v - break - } - } - if vertexB == nil { - t.Fatalf( - "Expected %q before %q. Couldn't find %q in:\n\n%s", - A, B, B, g.String()) - } - - // Look at ancestors - deps, err := g.Ancestors(vertexB) - if err != nil { - t.Fatalf("Error: %s in graph:\n\n%s", err, g.String()) - } - - // Make sure B is in there - for _, v := range deps.List() { - if dag.VertexName(v) == A { - // Success - return - } - } - - t.Fatalf( - "Expected %q before %q in:\n\n%s", - A, B, g.String()) -} diff --git a/internal/terraform/graph_walk.go b/internal/terraform/graph_walk.go deleted file mode 100644 index 5a0041cb4f1f..000000000000 --- a/internal/terraform/graph_walk.go +++ /dev/null @@ -1,25 +0,0 @@ -package terraform - -import ( - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -// GraphWalker is an interface that can be implemented that when used -// with Graph.Walk will invoke the given callbacks under certain events. -type GraphWalker interface { - EvalContext() EvalContext - EnterPath(addrs.ModuleInstance) EvalContext - ExitPath(addrs.ModuleInstance) - Execute(EvalContext, GraphNodeExecutable) tfdiags.Diagnostics -} - -// NullGraphWalker is a GraphWalker implementation that does nothing. -// This can be embedded within other GraphWalker implementations for easily -// implementing all the required functions. -type NullGraphWalker struct{} - -func (NullGraphWalker) EvalContext() EvalContext { return new(MockEvalContext) } -func (NullGraphWalker) EnterPath(addrs.ModuleInstance) EvalContext { return new(MockEvalContext) } -func (NullGraphWalker) ExitPath(addrs.ModuleInstance) {} -func (NullGraphWalker) Execute(EvalContext, GraphNodeExecutable) tfdiags.Diagnostics { return nil } diff --git a/internal/terraform/graph_walk_context.go b/internal/terraform/graph_walk_context.go deleted file mode 100644 index 806095405986..000000000000 --- a/internal/terraform/graph_walk_context.go +++ /dev/null @@ -1,137 +0,0 @@ -package terraform - -import ( - "context" - "sync" - - "github.com/zclconf/go-cty/cty" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/checks" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/instances" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/provisioners" - "github.com/hashicorp/terraform/internal/refactoring" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -// ContextGraphWalker is the GraphWalker implementation used with the -// Context struct to walk and evaluate the graph. -type ContextGraphWalker struct { - NullGraphWalker - - // Configurable values - Context *Context - State *states.SyncState // Used for safe concurrent access to state - RefreshState *states.SyncState // Used for safe concurrent access to state - PrevRunState *states.SyncState // Used for safe concurrent access to state - Changes *plans.ChangesSync // Used for safe concurrent writes to changes - Checks *checks.State // Used for safe concurrent writes of checkable objects and their check results - InstanceExpander *instances.Expander // Tracks our gradual expansion of module and resource instances - MoveResults refactoring.MoveResults // Read-only record of earlier processing of move statements - Operation walkOperation - StopContext context.Context - RootVariableValues InputValues - Config *configs.Config - - // This is an output. Do not set this, nor read it while a graph walk - // is in progress. - NonFatalDiagnostics tfdiags.Diagnostics - - once sync.Once - contexts map[string]*BuiltinEvalContext - contextLock sync.Mutex - variableValues map[string]map[string]cty.Value - variableValuesLock sync.Mutex - providerCache map[string]providers.Interface - providerSchemas map[string]*ProviderSchema - providerLock sync.Mutex - provisionerCache map[string]provisioners.Interface - provisionerSchemas map[string]*configschema.Block - provisionerLock sync.Mutex -} - -func (w *ContextGraphWalker) EnterPath(path addrs.ModuleInstance) EvalContext { - w.contextLock.Lock() - defer w.contextLock.Unlock() - - // If we already have a context for this path cached, use that - key := path.String() - if ctx, ok := w.contexts[key]; ok { - return ctx - } - - ctx := w.EvalContext().WithPath(path) - w.contexts[key] = ctx.(*BuiltinEvalContext) - return ctx -} - -func (w *ContextGraphWalker) EvalContext() EvalContext { - w.once.Do(w.init) - - // Our evaluator shares some locks with the main context and the walker - // so that we can safely run multiple evaluations at once across - // different modules. - evaluator := &Evaluator{ - Meta: w.Context.meta, - Config: w.Config, - Operation: w.Operation, - State: w.State, - Changes: w.Changes, - Plugins: w.Context.plugins, - VariableValues: w.variableValues, - VariableValuesLock: &w.variableValuesLock, - } - - ctx := &BuiltinEvalContext{ - StopContext: w.StopContext, - Hooks: w.Context.hooks, - InputValue: w.Context.uiInput, - InstanceExpanderValue: w.InstanceExpander, - Plugins: w.Context.plugins, - MoveResultsValue: w.MoveResults, - ProviderCache: w.providerCache, - ProviderInputConfig: w.Context.providerInputConfig, - ProviderLock: &w.providerLock, - ProvisionerCache: w.provisionerCache, - ProvisionerLock: &w.provisionerLock, - ChangesValue: w.Changes, - ChecksValue: w.Checks, - StateValue: w.State, - RefreshStateValue: w.RefreshState, - PrevRunStateValue: w.PrevRunState, - Evaluator: evaluator, - VariableValues: w.variableValues, - VariableValuesLock: &w.variableValuesLock, - } - - return ctx -} - -func (w *ContextGraphWalker) init() { - w.contexts = make(map[string]*BuiltinEvalContext) - w.providerCache = make(map[string]providers.Interface) - w.providerSchemas = make(map[string]*ProviderSchema) - w.provisionerCache = make(map[string]provisioners.Interface) - w.provisionerSchemas = make(map[string]*configschema.Block) - w.variableValues = make(map[string]map[string]cty.Value) - - // Populate root module variable values. Other modules will be populated - // during the graph walk. - w.variableValues[""] = make(map[string]cty.Value) - for k, iv := range w.RootVariableValues { - w.variableValues[""][k] = iv.Value - } -} - -func (w *ContextGraphWalker) Execute(ctx EvalContext, n GraphNodeExecutable) tfdiags.Diagnostics { - // Acquire a lock on the semaphore - w.Context.parallelSem.Acquire() - defer w.Context.parallelSem.Release() - - return n.Execute(ctx, w.Operation) -} diff --git a/internal/terraform/graph_walk_operation.go b/internal/terraform/graph_walk_operation.go deleted file mode 100644 index 798ff20e1392..000000000000 --- a/internal/terraform/graph_walk_operation.go +++ /dev/null @@ -1,17 +0,0 @@ -package terraform - -//go:generate go run golang.org/x/tools/cmd/stringer -type=walkOperation graph_walk_operation.go - -// walkOperation is an enum which tells the walkContext what to do. -type walkOperation byte - -const ( - walkInvalid walkOperation = iota - walkApply - walkPlan - walkPlanDestroy - walkValidate - walkDestroy - walkImport - walkEval // used just to prepare EvalContext for expression evaluation, with no other actions -) diff --git a/internal/terraform/graph_walk_test.go b/internal/terraform/graph_walk_test.go deleted file mode 100644 index 88b52a748163..000000000000 --- a/internal/terraform/graph_walk_test.go +++ /dev/null @@ -1,9 +0,0 @@ -package terraform - -import ( - "testing" -) - -func TestNullGraphWalker_impl(t *testing.T) { - var _ GraphWalker = NullGraphWalker{} -} diff --git a/internal/terraform/hook.go b/internal/terraform/hook.go deleted file mode 100644 index 7e927e8a5db7..000000000000 --- a/internal/terraform/hook.go +++ /dev/null @@ -1,145 +0,0 @@ -package terraform - -import ( - "github.com/zclconf/go-cty/cty" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" -) - -// HookAction is an enum of actions that can be taken as a result of a hook -// callback. This allows you to modify the behavior of Terraform at runtime. -type HookAction byte - -const ( - // HookActionContinue continues with processing as usual. - HookActionContinue HookAction = iota - - // HookActionHalt halts immediately: no more hooks are processed - // and the action that Terraform was about to take is cancelled. - HookActionHalt -) - -// Hook is the interface that must be implemented to hook into various -// parts of Terraform, allowing you to inspect or change behavior at runtime. -// -// There are MANY hook points into Terraform. If you only want to implement -// some hook points, but not all (which is the likely case), then embed the -// NilHook into your struct, which implements all of the interface but does -// nothing. Then, override only the functions you want to implement. -type Hook interface { - // PreApply and PostApply are called before and after an action for a - // single instance is applied. The error argument in PostApply is the - // error, if any, that was returned from the provider Apply call itself. - PreApply(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) - PostApply(addr addrs.AbsResourceInstance, gen states.Generation, newState cty.Value, err error) (HookAction, error) - - // PreDiff and PostDiff are called before and after a provider is given - // the opportunity to customize the proposed new state to produce the - // planned new state. - PreDiff(addr addrs.AbsResourceInstance, gen states.Generation, priorState, proposedNewState cty.Value) (HookAction, error) - PostDiff(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) - - // The provisioning hooks signal both the overall start end end of - // provisioning for a particular instance and of each of the individual - // configured provisioners for each instance. The sequence of these - // for a given instance might look something like this: - // - // PreProvisionInstance(aws_instance.foo[1], ...) - // PreProvisionInstanceStep(aws_instance.foo[1], "file") - // PostProvisionInstanceStep(aws_instance.foo[1], "file", nil) - // PreProvisionInstanceStep(aws_instance.foo[1], "remote-exec") - // ProvisionOutput(aws_instance.foo[1], "remote-exec", "Installing foo...") - // ProvisionOutput(aws_instance.foo[1], "remote-exec", "Configuring bar...") - // PostProvisionInstanceStep(aws_instance.foo[1], "remote-exec", nil) - // PostProvisionInstance(aws_instance.foo[1], ...) - // - // ProvisionOutput is called with output sent back by the provisioners. - // This will be called multiple times as output comes in, with each call - // representing one line of output. It cannot control whether the - // provisioner continues running. - PreProvisionInstance(addr addrs.AbsResourceInstance, state cty.Value) (HookAction, error) - PostProvisionInstance(addr addrs.AbsResourceInstance, state cty.Value) (HookAction, error) - PreProvisionInstanceStep(addr addrs.AbsResourceInstance, typeName string) (HookAction, error) - PostProvisionInstanceStep(addr addrs.AbsResourceInstance, typeName string, err error) (HookAction, error) - ProvisionOutput(addr addrs.AbsResourceInstance, typeName string, line string) - - // PreRefresh and PostRefresh are called before and after a single - // resource state is refreshed, respectively. - PreRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value) (HookAction, error) - PostRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value, newState cty.Value) (HookAction, error) - - // PreImportState and PostImportState are called before and after - // (respectively) each state import operation for a given resource address. - PreImportState(addr addrs.AbsResourceInstance, importID string) (HookAction, error) - PostImportState(addr addrs.AbsResourceInstance, imported []providers.ImportedResource) (HookAction, error) - - // PostStateUpdate is called each time the state is updated. It receives - // a deep copy of the state, which it may therefore access freely without - // any need for locks to protect from concurrent writes from the caller. - PostStateUpdate(new *states.State) (HookAction, error) -} - -// NilHook is a Hook implementation that does nothing. It exists only to -// simplify implementing hooks. You can embed this into your Hook implementation -// and only implement the functions you are interested in. -type NilHook struct{} - -var _ Hook = (*NilHook)(nil) - -func (*NilHook) PreApply(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) { - return HookActionContinue, nil -} - -func (*NilHook) PostApply(addr addrs.AbsResourceInstance, gen states.Generation, newState cty.Value, err error) (HookAction, error) { - return HookActionContinue, nil -} - -func (*NilHook) PreDiff(addr addrs.AbsResourceInstance, gen states.Generation, priorState, proposedNewState cty.Value) (HookAction, error) { - return HookActionContinue, nil -} - -func (*NilHook) PostDiff(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) { - return HookActionContinue, nil -} - -func (*NilHook) PreProvisionInstance(addr addrs.AbsResourceInstance, state cty.Value) (HookAction, error) { - return HookActionContinue, nil -} - -func (*NilHook) PostProvisionInstance(addr addrs.AbsResourceInstance, state cty.Value) (HookAction, error) { - return HookActionContinue, nil -} - -func (*NilHook) PreProvisionInstanceStep(addr addrs.AbsResourceInstance, typeName string) (HookAction, error) { - return HookActionContinue, nil -} - -func (*NilHook) PostProvisionInstanceStep(addr addrs.AbsResourceInstance, typeName string, err error) (HookAction, error) { - return HookActionContinue, nil -} - -func (*NilHook) ProvisionOutput(addr addrs.AbsResourceInstance, typeName string, line string) { -} - -func (*NilHook) PreRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value) (HookAction, error) { - return HookActionContinue, nil -} - -func (*NilHook) PostRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value, newState cty.Value) (HookAction, error) { - return HookActionContinue, nil -} - -func (*NilHook) PreImportState(addr addrs.AbsResourceInstance, importID string) (HookAction, error) { - return HookActionContinue, nil -} - -func (*NilHook) PostImportState(addr addrs.AbsResourceInstance, imported []providers.ImportedResource) (HookAction, error) { - return HookActionContinue, nil -} - -func (*NilHook) PostStateUpdate(new *states.State) (HookAction, error) { - return HookActionContinue, nil -} diff --git a/internal/terraform/hook_mock.go b/internal/terraform/hook_mock.go deleted file mode 100644 index 0511a5780504..000000000000 --- a/internal/terraform/hook_mock.go +++ /dev/null @@ -1,274 +0,0 @@ -package terraform - -import ( - "sync" - - "github.com/zclconf/go-cty/cty" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" -) - -// MockHook is an implementation of Hook that can be used for tests. -// It records all of its function calls. -type MockHook struct { - sync.Mutex - - PreApplyCalled bool - PreApplyAddr addrs.AbsResourceInstance - PreApplyGen states.Generation - PreApplyAction plans.Action - PreApplyPriorState cty.Value - PreApplyPlannedState cty.Value - PreApplyReturn HookAction - PreApplyError error - - PostApplyCalled bool - PostApplyAddr addrs.AbsResourceInstance - PostApplyGen states.Generation - PostApplyNewState cty.Value - PostApplyError error - PostApplyReturn HookAction - PostApplyReturnError error - PostApplyFn func(addrs.AbsResourceInstance, states.Generation, cty.Value, error) (HookAction, error) - - PreDiffCalled bool - PreDiffAddr addrs.AbsResourceInstance - PreDiffGen states.Generation - PreDiffPriorState cty.Value - PreDiffProposedState cty.Value - PreDiffReturn HookAction - PreDiffError error - - PostDiffCalled bool - PostDiffAddr addrs.AbsResourceInstance - PostDiffGen states.Generation - PostDiffAction plans.Action - PostDiffPriorState cty.Value - PostDiffPlannedState cty.Value - PostDiffReturn HookAction - PostDiffError error - - PreProvisionInstanceCalled bool - PreProvisionInstanceAddr addrs.AbsResourceInstance - PreProvisionInstanceState cty.Value - PreProvisionInstanceReturn HookAction - PreProvisionInstanceError error - - PostProvisionInstanceCalled bool - PostProvisionInstanceAddr addrs.AbsResourceInstance - PostProvisionInstanceState cty.Value - PostProvisionInstanceReturn HookAction - PostProvisionInstanceError error - - PreProvisionInstanceStepCalled bool - PreProvisionInstanceStepAddr addrs.AbsResourceInstance - PreProvisionInstanceStepProvisionerType string - PreProvisionInstanceStepReturn HookAction - PreProvisionInstanceStepError error - - PostProvisionInstanceStepCalled bool - PostProvisionInstanceStepAddr addrs.AbsResourceInstance - PostProvisionInstanceStepProvisionerType string - PostProvisionInstanceStepErrorArg error - PostProvisionInstanceStepReturn HookAction - PostProvisionInstanceStepError error - - ProvisionOutputCalled bool - ProvisionOutputAddr addrs.AbsResourceInstance - ProvisionOutputProvisionerType string - ProvisionOutputMessage string - - PreRefreshCalled bool - PreRefreshAddr addrs.AbsResourceInstance - PreRefreshGen states.Generation - PreRefreshPriorState cty.Value - PreRefreshReturn HookAction - PreRefreshError error - - PostRefreshCalled bool - PostRefreshAddr addrs.AbsResourceInstance - PostRefreshGen states.Generation - PostRefreshPriorState cty.Value - PostRefreshNewState cty.Value - PostRefreshReturn HookAction - PostRefreshError error - - PreImportStateCalled bool - PreImportStateAddr addrs.AbsResourceInstance - PreImportStateID string - PreImportStateReturn HookAction - PreImportStateError error - - PostImportStateCalled bool - PostImportStateAddr addrs.AbsResourceInstance - PostImportStateNewStates []providers.ImportedResource - PostImportStateReturn HookAction - PostImportStateError error - - PostStateUpdateCalled bool - PostStateUpdateState *states.State - PostStateUpdateReturn HookAction - PostStateUpdateError error -} - -var _ Hook = (*MockHook)(nil) - -func (h *MockHook) PreApply(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) { - h.Lock() - defer h.Unlock() - - h.PreApplyCalled = true - h.PreApplyAddr = addr - h.PreApplyGen = gen - h.PreApplyAction = action - h.PreApplyPriorState = priorState - h.PreApplyPlannedState = plannedNewState - return h.PreApplyReturn, h.PreApplyError -} - -func (h *MockHook) PostApply(addr addrs.AbsResourceInstance, gen states.Generation, newState cty.Value, err error) (HookAction, error) { - h.Lock() - defer h.Unlock() - - h.PostApplyCalled = true - h.PostApplyAddr = addr - h.PostApplyGen = gen - h.PostApplyNewState = newState - h.PostApplyError = err - - if h.PostApplyFn != nil { - return h.PostApplyFn(addr, gen, newState, err) - } - - return h.PostApplyReturn, h.PostApplyReturnError -} - -func (h *MockHook) PreDiff(addr addrs.AbsResourceInstance, gen states.Generation, priorState, proposedNewState cty.Value) (HookAction, error) { - h.Lock() - defer h.Unlock() - - h.PreDiffCalled = true - h.PreDiffAddr = addr - h.PreDiffGen = gen - h.PreDiffPriorState = priorState - h.PreDiffProposedState = proposedNewState - return h.PreDiffReturn, h.PreDiffError -} - -func (h *MockHook) PostDiff(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) { - h.Lock() - defer h.Unlock() - - h.PostDiffCalled = true - h.PostDiffAddr = addr - h.PostDiffGen = gen - h.PostDiffAction = action - h.PostDiffPriorState = priorState - h.PostDiffPlannedState = plannedNewState - return h.PostDiffReturn, h.PostDiffError -} - -func (h *MockHook) PreProvisionInstance(addr addrs.AbsResourceInstance, state cty.Value) (HookAction, error) { - h.Lock() - defer h.Unlock() - - h.PreProvisionInstanceCalled = true - h.PreProvisionInstanceAddr = addr - h.PreProvisionInstanceState = state - return h.PreProvisionInstanceReturn, h.PreProvisionInstanceError -} - -func (h *MockHook) PostProvisionInstance(addr addrs.AbsResourceInstance, state cty.Value) (HookAction, error) { - h.Lock() - defer h.Unlock() - - h.PostProvisionInstanceCalled = true - h.PostProvisionInstanceAddr = addr - h.PostProvisionInstanceState = state - return h.PostProvisionInstanceReturn, h.PostProvisionInstanceError -} - -func (h *MockHook) PreProvisionInstanceStep(addr addrs.AbsResourceInstance, typeName string) (HookAction, error) { - h.Lock() - defer h.Unlock() - - h.PreProvisionInstanceStepCalled = true - h.PreProvisionInstanceStepAddr = addr - h.PreProvisionInstanceStepProvisionerType = typeName - return h.PreProvisionInstanceStepReturn, h.PreProvisionInstanceStepError -} - -func (h *MockHook) PostProvisionInstanceStep(addr addrs.AbsResourceInstance, typeName string, err error) (HookAction, error) { - h.Lock() - defer h.Unlock() - - h.PostProvisionInstanceStepCalled = true - h.PostProvisionInstanceStepAddr = addr - h.PostProvisionInstanceStepProvisionerType = typeName - h.PostProvisionInstanceStepErrorArg = err - return h.PostProvisionInstanceStepReturn, h.PostProvisionInstanceStepError -} - -func (h *MockHook) ProvisionOutput(addr addrs.AbsResourceInstance, typeName string, line string) { - h.Lock() - defer h.Unlock() - - h.ProvisionOutputCalled = true - h.ProvisionOutputAddr = addr - h.ProvisionOutputProvisionerType = typeName - h.ProvisionOutputMessage = line -} - -func (h *MockHook) PreRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value) (HookAction, error) { - h.Lock() - defer h.Unlock() - - h.PreRefreshCalled = true - h.PreRefreshAddr = addr - h.PreRefreshGen = gen - h.PreRefreshPriorState = priorState - return h.PreRefreshReturn, h.PreRefreshError -} - -func (h *MockHook) PostRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value, newState cty.Value) (HookAction, error) { - h.Lock() - defer h.Unlock() - - h.PostRefreshCalled = true - h.PostRefreshAddr = addr - h.PostRefreshPriorState = priorState - h.PostRefreshNewState = newState - return h.PostRefreshReturn, h.PostRefreshError -} - -func (h *MockHook) PreImportState(addr addrs.AbsResourceInstance, importID string) (HookAction, error) { - h.Lock() - defer h.Unlock() - - h.PreImportStateCalled = true - h.PreImportStateAddr = addr - h.PreImportStateID = importID - return h.PreImportStateReturn, h.PreImportStateError -} - -func (h *MockHook) PostImportState(addr addrs.AbsResourceInstance, imported []providers.ImportedResource) (HookAction, error) { - h.Lock() - defer h.Unlock() - - h.PostImportStateCalled = true - h.PostImportStateAddr = addr - h.PostImportStateNewStates = imported - return h.PostImportStateReturn, h.PostImportStateError -} - -func (h *MockHook) PostStateUpdate(new *states.State) (HookAction, error) { - h.Lock() - defer h.Unlock() - - h.PostStateUpdateCalled = true - h.PostStateUpdateState = new - return h.PostStateUpdateReturn, h.PostStateUpdateError -} diff --git a/internal/terraform/hook_stop.go b/internal/terraform/hook_stop.go deleted file mode 100644 index 2d4144e56090..000000000000 --- a/internal/terraform/hook_stop.go +++ /dev/null @@ -1,97 +0,0 @@ -package terraform - -import ( - "errors" - "sync/atomic" - - "github.com/zclconf/go-cty/cty" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" -) - -// stopHook is a private Hook implementation that Terraform uses to -// signal when to stop or cancel actions. -type stopHook struct { - stop uint32 -} - -var _ Hook = (*stopHook)(nil) - -func (h *stopHook) PreApply(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) { - return h.hook() -} - -func (h *stopHook) PostApply(addr addrs.AbsResourceInstance, gen states.Generation, newState cty.Value, err error) (HookAction, error) { - return h.hook() -} - -func (h *stopHook) PreDiff(addr addrs.AbsResourceInstance, gen states.Generation, priorState, proposedNewState cty.Value) (HookAction, error) { - return h.hook() -} - -func (h *stopHook) PostDiff(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) { - return h.hook() -} - -func (h *stopHook) PreProvisionInstance(addr addrs.AbsResourceInstance, state cty.Value) (HookAction, error) { - return h.hook() -} - -func (h *stopHook) PostProvisionInstance(addr addrs.AbsResourceInstance, state cty.Value) (HookAction, error) { - return h.hook() -} - -func (h *stopHook) PreProvisionInstanceStep(addr addrs.AbsResourceInstance, typeName string) (HookAction, error) { - return h.hook() -} - -func (h *stopHook) PostProvisionInstanceStep(addr addrs.AbsResourceInstance, typeName string, err error) (HookAction, error) { - return h.hook() -} - -func (h *stopHook) ProvisionOutput(addr addrs.AbsResourceInstance, typeName string, line string) { -} - -func (h *stopHook) PreRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value) (HookAction, error) { - return h.hook() -} - -func (h *stopHook) PostRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value, newState cty.Value) (HookAction, error) { - return h.hook() -} - -func (h *stopHook) PreImportState(addr addrs.AbsResourceInstance, importID string) (HookAction, error) { - return h.hook() -} - -func (h *stopHook) PostImportState(addr addrs.AbsResourceInstance, imported []providers.ImportedResource) (HookAction, error) { - return h.hook() -} - -func (h *stopHook) PostStateUpdate(new *states.State) (HookAction, error) { - return h.hook() -} - -func (h *stopHook) hook() (HookAction, error) { - if h.Stopped() { - return HookActionHalt, errors.New("execution halted") - } - - return HookActionContinue, nil -} - -// reset should be called within the lock context -func (h *stopHook) Reset() { - atomic.StoreUint32(&h.stop, 0) -} - -func (h *stopHook) Stop() { - atomic.StoreUint32(&h.stop, 1) -} - -func (h *stopHook) Stopped() bool { - return atomic.LoadUint32(&h.stop) == 1 -} diff --git a/internal/terraform/hook_stop_test.go b/internal/terraform/hook_stop_test.go deleted file mode 100644 index 2c30231f9608..000000000000 --- a/internal/terraform/hook_stop_test.go +++ /dev/null @@ -1,9 +0,0 @@ -package terraform - -import ( - "testing" -) - -func TestStopHook_impl(t *testing.T) { - var _ Hook = new(stopHook) -} diff --git a/internal/terraform/hook_test.go b/internal/terraform/hook_test.go deleted file mode 100644 index 0d5267dafaca..000000000000 --- a/internal/terraform/hook_test.go +++ /dev/null @@ -1,132 +0,0 @@ -package terraform - -import ( - "sync" - "testing" - - "github.com/zclconf/go-cty/cty" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" -) - -func TestNilHook_impl(t *testing.T) { - var _ Hook = new(NilHook) -} - -// testHook is a Hook implementation that logs the calls it receives. -// It is intended for testing that core code is emitting the correct hooks -// for a given situation. -type testHook struct { - mu sync.Mutex - Calls []*testHookCall -} - -var _ Hook = (*testHook)(nil) - -// testHookCall represents a single call in testHook. -// This hook just logs string names to make it easy to write "want" expressions -// in tests that can DeepEqual against the real calls. -type testHookCall struct { - Action string - InstanceID string -} - -func (h *testHook) PreApply(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) { - h.mu.Lock() - defer h.mu.Unlock() - h.Calls = append(h.Calls, &testHookCall{"PreApply", addr.String()}) - return HookActionContinue, nil -} - -func (h *testHook) PostApply(addr addrs.AbsResourceInstance, gen states.Generation, newState cty.Value, err error) (HookAction, error) { - h.mu.Lock() - defer h.mu.Unlock() - h.Calls = append(h.Calls, &testHookCall{"PostApply", addr.String()}) - return HookActionContinue, nil -} - -func (h *testHook) PreDiff(addr addrs.AbsResourceInstance, gen states.Generation, priorState, proposedNewState cty.Value) (HookAction, error) { - h.mu.Lock() - defer h.mu.Unlock() - h.Calls = append(h.Calls, &testHookCall{"PreDiff", addr.String()}) - return HookActionContinue, nil -} - -func (h *testHook) PostDiff(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) { - h.mu.Lock() - defer h.mu.Unlock() - h.Calls = append(h.Calls, &testHookCall{"PostDiff", addr.String()}) - return HookActionContinue, nil -} - -func (h *testHook) PreProvisionInstance(addr addrs.AbsResourceInstance, state cty.Value) (HookAction, error) { - h.mu.Lock() - defer h.mu.Unlock() - h.Calls = append(h.Calls, &testHookCall{"PreProvisionInstance", addr.String()}) - return HookActionContinue, nil -} - -func (h *testHook) PostProvisionInstance(addr addrs.AbsResourceInstance, state cty.Value) (HookAction, error) { - h.mu.Lock() - defer h.mu.Unlock() - h.Calls = append(h.Calls, &testHookCall{"PostProvisionInstance", addr.String()}) - return HookActionContinue, nil -} - -func (h *testHook) PreProvisionInstanceStep(addr addrs.AbsResourceInstance, typeName string) (HookAction, error) { - h.mu.Lock() - defer h.mu.Unlock() - h.Calls = append(h.Calls, &testHookCall{"PreProvisionInstanceStep", addr.String()}) - return HookActionContinue, nil -} - -func (h *testHook) PostProvisionInstanceStep(addr addrs.AbsResourceInstance, typeName string, err error) (HookAction, error) { - h.mu.Lock() - defer h.mu.Unlock() - h.Calls = append(h.Calls, &testHookCall{"PostProvisionInstanceStep", addr.String()}) - return HookActionContinue, nil -} - -func (h *testHook) ProvisionOutput(addr addrs.AbsResourceInstance, typeName string, line string) { - h.mu.Lock() - defer h.mu.Unlock() - h.Calls = append(h.Calls, &testHookCall{"ProvisionOutput", addr.String()}) -} - -func (h *testHook) PreRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value) (HookAction, error) { - h.mu.Lock() - defer h.mu.Unlock() - h.Calls = append(h.Calls, &testHookCall{"PreRefresh", addr.String()}) - return HookActionContinue, nil -} - -func (h *testHook) PostRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value, newState cty.Value) (HookAction, error) { - h.mu.Lock() - defer h.mu.Unlock() - h.Calls = append(h.Calls, &testHookCall{"PostRefresh", addr.String()}) - return HookActionContinue, nil -} - -func (h *testHook) PreImportState(addr addrs.AbsResourceInstance, importID string) (HookAction, error) { - h.mu.Lock() - defer h.mu.Unlock() - h.Calls = append(h.Calls, &testHookCall{"PreImportState", addr.String()}) - return HookActionContinue, nil -} - -func (h *testHook) PostImportState(addr addrs.AbsResourceInstance, imported []providers.ImportedResource) (HookAction, error) { - h.mu.Lock() - defer h.mu.Unlock() - h.Calls = append(h.Calls, &testHookCall{"PostImportState", addr.String()}) - return HookActionContinue, nil -} - -func (h *testHook) PostStateUpdate(new *states.State) (HookAction, error) { - h.mu.Lock() - defer h.mu.Unlock() - h.Calls = append(h.Calls, &testHookCall{"PostStateUpdate", ""}) - return HookActionContinue, nil -} diff --git a/internal/terraform/instance_expanders.go b/internal/terraform/instance_expanders.go deleted file mode 100644 index b3733afb0afd..000000000000 --- a/internal/terraform/instance_expanders.go +++ /dev/null @@ -1,7 +0,0 @@ -package terraform - -// graphNodeExpandsInstances is implemented by nodes that causes instances to -// be registered in the instances.Expander. -type graphNodeExpandsInstances interface { - expandsInstances() -} diff --git a/internal/terraform/marks.go b/internal/terraform/marks.go deleted file mode 100644 index 8e2a3260721f..000000000000 --- a/internal/terraform/marks.go +++ /dev/null @@ -1,39 +0,0 @@ -package terraform - -import ( - "fmt" - "sort" - - "github.com/zclconf/go-cty/cty" -) - -// marksEqual compares 2 unordered sets of PathValue marks for equality, with -// the comparison using the cty.PathValueMarks.Equal method. -func marksEqual(a, b []cty.PathValueMarks) bool { - if len(a) == 0 && len(b) == 0 { - return true - } - - if len(a) != len(b) { - return false - } - - less := func(s []cty.PathValueMarks) func(i, j int) bool { - return func(i, j int) bool { - // the sort only needs to be consistent, so use the GoString format - // to get a comparable value - return fmt.Sprintf("%#v", s[i]) < fmt.Sprintf("%#v", s[j]) - } - } - - sort.Slice(a, less(a)) - sort.Slice(b, less(b)) - - for i := 0; i < len(a); i++ { - if !a[i].Equal(b[i]) { - return false - } - } - - return true -} diff --git a/internal/terraform/marks_test.go b/internal/terraform/marks_test.go deleted file mode 100644 index d3f449187746..000000000000 --- a/internal/terraform/marks_test.go +++ /dev/null @@ -1,105 +0,0 @@ -package terraform - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform/internal/lang/marks" - "github.com/zclconf/go-cty/cty" -) - -func TestMarksEqual(t *testing.T) { - for i, tc := range []struct { - a, b []cty.PathValueMarks - equal bool - }{ - { - []cty.PathValueMarks{ - cty.PathValueMarks{Path: cty.Path{cty.GetAttrStep{Name: "a"}}, Marks: cty.NewValueMarks(marks.Sensitive)}, - }, - []cty.PathValueMarks{ - cty.PathValueMarks{Path: cty.Path{cty.GetAttrStep{Name: "a"}}, Marks: cty.NewValueMarks(marks.Sensitive)}, - }, - true, - }, - { - []cty.PathValueMarks{ - cty.PathValueMarks{Path: cty.Path{cty.GetAttrStep{Name: "a"}}, Marks: cty.NewValueMarks(marks.Sensitive)}, - }, - []cty.PathValueMarks{ - cty.PathValueMarks{Path: cty.Path{cty.GetAttrStep{Name: "A"}}, Marks: cty.NewValueMarks(marks.Sensitive)}, - }, - false, - }, - { - []cty.PathValueMarks{ - cty.PathValueMarks{Path: cty.Path{cty.GetAttrStep{Name: "a"}}, Marks: cty.NewValueMarks(marks.Sensitive)}, - cty.PathValueMarks{Path: cty.Path{cty.GetAttrStep{Name: "b"}}, Marks: cty.NewValueMarks(marks.Sensitive)}, - cty.PathValueMarks{Path: cty.Path{cty.GetAttrStep{Name: "c"}}, Marks: cty.NewValueMarks(marks.Sensitive)}, - }, - []cty.PathValueMarks{ - cty.PathValueMarks{Path: cty.Path{cty.GetAttrStep{Name: "b"}}, Marks: cty.NewValueMarks(marks.Sensitive)}, - cty.PathValueMarks{Path: cty.Path{cty.GetAttrStep{Name: "c"}}, Marks: cty.NewValueMarks(marks.Sensitive)}, - cty.PathValueMarks{Path: cty.Path{cty.GetAttrStep{Name: "a"}}, Marks: cty.NewValueMarks(marks.Sensitive)}, - }, - true, - }, - { - []cty.PathValueMarks{ - cty.PathValueMarks{ - Path: cty.Path{cty.GetAttrStep{Name: "a"}, cty.GetAttrStep{Name: "b"}}, - Marks: cty.NewValueMarks(marks.Sensitive), - }, - cty.PathValueMarks{ - Path: cty.Path{cty.GetAttrStep{Name: "a"}, cty.GetAttrStep{Name: "c"}}, - Marks: cty.NewValueMarks(marks.Sensitive), - }, - }, - []cty.PathValueMarks{ - cty.PathValueMarks{ - Path: cty.Path{cty.GetAttrStep{Name: "a"}, cty.GetAttrStep{Name: "c"}}, - Marks: cty.NewValueMarks(marks.Sensitive), - }, - cty.PathValueMarks{ - Path: cty.Path{cty.GetAttrStep{Name: "a"}, cty.GetAttrStep{Name: "b"}}, - Marks: cty.NewValueMarks(marks.Sensitive), - }, - }, - true, - }, - { - []cty.PathValueMarks{ - cty.PathValueMarks{Path: cty.Path{cty.GetAttrStep{Name: "a"}}, Marks: cty.NewValueMarks(marks.Sensitive)}, - }, - []cty.PathValueMarks{ - cty.PathValueMarks{Path: cty.Path{cty.GetAttrStep{Name: "b"}}, Marks: cty.NewValueMarks(marks.Sensitive)}, - }, - false, - }, - { - nil, - nil, - true, - }, - { - []cty.PathValueMarks{ - cty.PathValueMarks{Path: cty.Path{cty.GetAttrStep{Name: "a"}}, Marks: cty.NewValueMarks(marks.Sensitive)}, - }, - nil, - false, - }, - { - nil, - []cty.PathValueMarks{ - cty.PathValueMarks{Path: cty.Path{cty.GetAttrStep{Name: "a"}}, Marks: cty.NewValueMarks(marks.Sensitive)}, - }, - false, - }, - } { - t.Run(fmt.Sprint(i), func(t *testing.T) { - if marksEqual(tc.a, tc.b) != tc.equal { - t.Fatalf("marksEqual(\n%#v,\n%#v,\n) != %t\n", tc.a, tc.b, tc.equal) - } - }) - } -} diff --git a/internal/terraform/node_data_destroy.go b/internal/terraform/node_data_destroy.go deleted file mode 100644 index 0e81bb9c45d5..000000000000 --- a/internal/terraform/node_data_destroy.go +++ /dev/null @@ -1,24 +0,0 @@ -package terraform - -import ( - "log" - - "github.com/hashicorp/terraform/internal/tfdiags" -) - -// NodeDestroyableDataResourceInstance represents a resource that is "destroyable": -// it is ready to be destroyed. -type NodeDestroyableDataResourceInstance struct { - *NodeAbstractResourceInstance -} - -var ( - _ GraphNodeExecutable = (*NodeDestroyableDataResourceInstance)(nil) -) - -// GraphNodeExecutable -func (n *NodeDestroyableDataResourceInstance) Execute(ctx EvalContext, op walkOperation) tfdiags.Diagnostics { - log.Printf("[TRACE] NodeDestroyableDataResourceInstance: removing state object for %s", n.Addr) - ctx.State().SetResourceInstanceCurrent(n.Addr, nil, n.ResolvedProvider) - return nil -} diff --git a/internal/terraform/node_data_destroy_test.go b/internal/terraform/node_data_destroy_test.go deleted file mode 100644 index f399ee4183c4..000000000000 --- a/internal/terraform/node_data_destroy_test.go +++ /dev/null @@ -1,48 +0,0 @@ -package terraform - -import ( - "testing" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/states" -) - -func TestNodeDataDestroyExecute(t *testing.T) { - state := states.NewState() - state.Module(addrs.RootModuleInstance).SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.DataResourceMode, - Type: "test_instance", - Name: "foo", - }.Instance(addrs.NoKey), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"dynamic":{"type":"string","value":"hello"}}`), - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("test"), - Module: addrs.RootModule, - }, - ) - ctx := &MockEvalContext{ - StateState: state.SyncWrapper(), - } - - node := NodeDestroyableDataResourceInstance{&NodeAbstractResourceInstance{ - Addr: addrs.Resource{ - Mode: addrs.DataResourceMode, - Type: "test_instance", - Name: "foo", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - }} - - diags := node.Execute(ctx, walkApply) - if diags.HasErrors() { - t.Fatalf("unexpected error: %v", diags.Err()) - } - - // verify resource removed from state - if state.HasManagedResourceInstanceObjects() { - t.Fatal("resources still in state after NodeDataDestroy.Execute") - } -} diff --git a/internal/terraform/node_local.go b/internal/terraform/node_local.go deleted file mode 100644 index f194b9cc82a2..000000000000 --- a/internal/terraform/node_local.go +++ /dev/null @@ -1,180 +0,0 @@ -package terraform - -import ( - "fmt" - "log" - - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/dag" - "github.com/hashicorp/terraform/internal/lang" - "github.com/hashicorp/terraform/internal/tfdiags" - "github.com/zclconf/go-cty/cty" -) - -// nodeExpandLocal represents a named local value in a configuration module, -// which has not yet been expanded. -type nodeExpandLocal struct { - Addr addrs.LocalValue - Module addrs.Module - Config *configs.Local -} - -var ( - _ GraphNodeReferenceable = (*nodeExpandLocal)(nil) - _ GraphNodeReferencer = (*nodeExpandLocal)(nil) - _ GraphNodeDynamicExpandable = (*nodeExpandLocal)(nil) - _ graphNodeTemporaryValue = (*nodeExpandLocal)(nil) - _ graphNodeExpandsInstances = (*nodeExpandLocal)(nil) -) - -func (n *nodeExpandLocal) expandsInstances() {} - -// graphNodeTemporaryValue -func (n *nodeExpandLocal) temporaryValue() bool { - return true -} - -func (n *nodeExpandLocal) Name() string { - path := n.Module.String() - addr := n.Addr.String() + " (expand)" - - if path != "" { - return path + "." + addr - } - return addr -} - -// GraphNodeModulePath -func (n *nodeExpandLocal) ModulePath() addrs.Module { - return n.Module -} - -// GraphNodeReferenceable -func (n *nodeExpandLocal) ReferenceableAddrs() []addrs.Referenceable { - return []addrs.Referenceable{n.Addr} -} - -// GraphNodeReferencer -func (n *nodeExpandLocal) References() []*addrs.Reference { - refs, _ := lang.ReferencesInExpr(n.Config.Expr) - return refs -} - -func (n *nodeExpandLocal) DynamicExpand(ctx EvalContext) (*Graph, error) { - var g Graph - expander := ctx.InstanceExpander() - for _, module := range expander.ExpandModule(n.Module) { - o := &NodeLocal{ - Addr: n.Addr.Absolute(module), - Config: n.Config, - } - log.Printf("[TRACE] Expanding local: adding %s as %T", o.Addr.String(), o) - g.Add(o) - } - addRootNodeToGraph(&g) - return &g, nil -} - -// NodeLocal represents a named local value in a particular module. -// -// Local value nodes only have one operation, common to all walk types: -// evaluate the result and place it in state. -type NodeLocal struct { - Addr addrs.AbsLocalValue - Config *configs.Local -} - -var ( - _ GraphNodeModuleInstance = (*NodeLocal)(nil) - _ GraphNodeReferenceable = (*NodeLocal)(nil) - _ GraphNodeReferencer = (*NodeLocal)(nil) - _ GraphNodeExecutable = (*NodeLocal)(nil) - _ graphNodeTemporaryValue = (*NodeLocal)(nil) - _ dag.GraphNodeDotter = (*NodeLocal)(nil) -) - -// graphNodeTemporaryValue -func (n *NodeLocal) temporaryValue() bool { - return true -} - -func (n *NodeLocal) Name() string { - return n.Addr.String() -} - -// GraphNodeModuleInstance -func (n *NodeLocal) Path() addrs.ModuleInstance { - return n.Addr.Module -} - -// GraphNodeModulePath -func (n *NodeLocal) ModulePath() addrs.Module { - return n.Addr.Module.Module() -} - -// GraphNodeReferenceable -func (n *NodeLocal) ReferenceableAddrs() []addrs.Referenceable { - return []addrs.Referenceable{n.Addr.LocalValue} -} - -// GraphNodeReferencer -func (n *NodeLocal) References() []*addrs.Reference { - refs, _ := lang.ReferencesInExpr(n.Config.Expr) - return refs -} - -// GraphNodeExecutable -// NodeLocal.Execute is an Execute implementation that evaluates the -// expression for a local value and writes it into a transient part of -// the state. -func (n *NodeLocal) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) { - expr := n.Config.Expr - addr := n.Addr.LocalValue - - // We ignore diags here because any problems we might find will be found - // again in EvaluateExpr below. - refs, _ := lang.ReferencesInExpr(expr) - for _, ref := range refs { - if ref.Subject == addr { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Self-referencing local value", - Detail: fmt.Sprintf("Local value %s cannot use its own result as part of its expression.", addr), - Subject: ref.SourceRange.ToHCL().Ptr(), - Context: expr.Range().Ptr(), - }) - } - } - if diags.HasErrors() { - return diags - } - - val, moreDiags := ctx.EvaluateExpr(expr, cty.DynamicPseudoType, nil) - diags = diags.Append(moreDiags) - if moreDiags.HasErrors() { - return diags - } - - state := ctx.State() - if state == nil { - diags = diags.Append(fmt.Errorf("cannot write local value to nil state")) - return diags - } - - state.SetLocalValue(addr.Absolute(ctx.Path()), val) - - return diags -} - -// dag.GraphNodeDotter impl. -func (n *NodeLocal) DotNode(name string, opts *dag.DotOpts) *dag.DotNode { - return &dag.DotNode{ - Name: name, - Attrs: map[string]string{ - "label": n.Name(), - "shape": "note", - }, - } -} diff --git a/internal/terraform/node_local_test.go b/internal/terraform/node_local_test.go deleted file mode 100644 index c79f05eabf7e..000000000000 --- a/internal/terraform/node_local_test.go +++ /dev/null @@ -1,85 +0,0 @@ -package terraform - -import ( - "reflect" - "testing" - - "github.com/davecgh/go-spew/spew" - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/zclconf/go-cty/cty" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/hcl2shim" - "github.com/hashicorp/terraform/internal/states" -) - -func TestNodeLocalExecute(t *testing.T) { - tests := []struct { - Value string - Want interface{} - Err bool - }{ - { - "hello!", - "hello!", - false, - }, - { - "", - "", - false, - }, - { - "Hello, ${local.foo}", - nil, - true, // self-referencing - }, - } - - for _, test := range tests { - t.Run(test.Value, func(t *testing.T) { - expr, diags := hclsyntax.ParseTemplate([]byte(test.Value), "", hcl.Pos{Line: 1, Column: 1}) - if diags.HasErrors() { - t.Fatal(diags.Error()) - } - - n := &NodeLocal{ - Addr: addrs.LocalValue{Name: "foo"}.Absolute(addrs.RootModuleInstance), - Config: &configs.Local{ - Expr: expr, - }, - } - ctx := &MockEvalContext{ - StateState: states.NewState().SyncWrapper(), - - EvaluateExprResult: hcl2shim.HCL2ValueFromConfigValue(test.Want), - } - - err := n.Execute(ctx, walkApply) - if (err != nil) != test.Err { - if err != nil { - t.Errorf("unexpected error: %s", err) - } else { - t.Errorf("successful Eval; want error") - } - } - - ms := ctx.StateState.Module(addrs.RootModuleInstance) - gotLocals := ms.LocalValues - wantLocals := map[string]cty.Value{} - if test.Want != nil { - wantLocals["foo"] = hcl2shim.HCL2ValueFromConfigValue(test.Want) - } - - if !reflect.DeepEqual(gotLocals, wantLocals) { - t.Errorf( - "wrong locals after Eval\ngot: %swant: %s", - spew.Sdump(gotLocals), spew.Sdump(wantLocals), - ) - } - }) - } - -} diff --git a/internal/terraform/node_module_expand.go b/internal/terraform/node_module_expand.go deleted file mode 100644 index 28ec2b4e36e6..000000000000 --- a/internal/terraform/node_module_expand.go +++ /dev/null @@ -1,252 +0,0 @@ -package terraform - -import ( - "log" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/dag" - "github.com/hashicorp/terraform/internal/lang" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -type ConcreteModuleNodeFunc func(n *nodeExpandModule) dag.Vertex - -// nodeExpandModule represents a module call in the configuration that -// might expand into multiple module instances depending on how it is -// configured. -type nodeExpandModule struct { - Addr addrs.Module - Config *configs.Module - ModuleCall *configs.ModuleCall -} - -var ( - _ GraphNodeExecutable = (*nodeExpandModule)(nil) - _ GraphNodeReferencer = (*nodeExpandModule)(nil) - _ GraphNodeReferenceOutside = (*nodeExpandModule)(nil) - _ graphNodeExpandsInstances = (*nodeExpandModule)(nil) -) - -func (n *nodeExpandModule) expandsInstances() {} - -func (n *nodeExpandModule) Name() string { - return n.Addr.String() + " (expand)" -} - -// GraphNodeModulePath implementation -func (n *nodeExpandModule) ModulePath() addrs.Module { - return n.Addr -} - -// GraphNodeReferencer implementation -func (n *nodeExpandModule) References() []*addrs.Reference { - var refs []*addrs.Reference - - if n.ModuleCall == nil { - return nil - } - - refs = append(refs, n.DependsOn()...) - - // Expansion only uses the count and for_each expressions, so this - // particular graph node only refers to those. - // Individual variable values in the module call definition might also - // refer to other objects, but that's handled by - // NodeApplyableModuleVariable. - // - // Because our Path method returns the module instance that contains - // our call, these references will be correctly interpreted as being - // in the calling module's namespace, not the namespaces of any of the - // child module instances we might expand to during our evaluation. - - if n.ModuleCall.Count != nil { - countRefs, _ := lang.ReferencesInExpr(n.ModuleCall.Count) - refs = append(refs, countRefs...) - } - if n.ModuleCall.ForEach != nil { - forEachRefs, _ := lang.ReferencesInExpr(n.ModuleCall.ForEach) - refs = append(refs, forEachRefs...) - } - return refs -} - -func (n *nodeExpandModule) DependsOn() []*addrs.Reference { - if n.ModuleCall == nil { - return nil - } - - var refs []*addrs.Reference - for _, traversal := range n.ModuleCall.DependsOn { - ref, diags := addrs.ParseRef(traversal) - if diags.HasErrors() { - // We ignore this here, because this isn't a suitable place to return - // errors. This situation should be caught and rejected during - // validation. - log.Printf("[ERROR] Can't parse %#v from depends_on as reference: %s", traversal, diags.Err()) - continue - } - - refs = append(refs, ref) - } - - return refs -} - -// GraphNodeReferenceOutside -func (n *nodeExpandModule) ReferenceOutside() (selfPath, referencePath addrs.Module) { - return n.Addr, n.Addr.Parent() -} - -// GraphNodeExecutable -func (n *nodeExpandModule) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) { - expander := ctx.InstanceExpander() - _, call := n.Addr.Call() - - // nodeExpandModule itself does not have visibility into how its ancestors - // were expanded, so we use the expander here to provide all possible paths - // to our module, and register module instances with each of them. - for _, module := range expander.ExpandModule(n.Addr.Parent()) { - ctx = ctx.WithPath(module) - switch { - case n.ModuleCall.Count != nil: - count, ctDiags := evaluateCountExpression(n.ModuleCall.Count, ctx) - diags = diags.Append(ctDiags) - if diags.HasErrors() { - return diags - } - expander.SetModuleCount(module, call, count) - - case n.ModuleCall.ForEach != nil: - forEach, feDiags := evaluateForEachExpression(n.ModuleCall.ForEach, ctx) - diags = diags.Append(feDiags) - if diags.HasErrors() { - return diags - } - expander.SetModuleForEach(module, call, forEach) - - default: - expander.SetModuleSingle(module, call) - } - } - - return diags - -} - -// nodeCloseModule represents an expanded module during apply, and is visited -// after all other module instance nodes. This node will depend on all module -// instance resource and outputs, and anything depending on the module should -// wait on this node. -// Besides providing a root node for dependency ordering, nodeCloseModule also -// cleans up state after all the module nodes have been evaluated, removing -// empty resources and modules from the state. -// The root module instance also closes any remaining provisioner plugins which -// do not have a lifecycle controlled by individual graph nodes. -type nodeCloseModule struct { - Addr addrs.Module -} - -var ( - _ GraphNodeReferenceable = (*nodeCloseModule)(nil) - _ GraphNodeReferenceOutside = (*nodeCloseModule)(nil) - _ GraphNodeExecutable = (*nodeCloseModule)(nil) -) - -func (n *nodeCloseModule) ModulePath() addrs.Module { - return n.Addr -} - -func (n *nodeCloseModule) ReferenceOutside() (selfPath, referencePath addrs.Module) { - return n.Addr.Parent(), n.Addr -} - -func (n *nodeCloseModule) ReferenceableAddrs() []addrs.Referenceable { - _, call := n.Addr.Call() - return []addrs.Referenceable{ - call, - } -} - -func (n *nodeCloseModule) Name() string { - if len(n.Addr) == 0 { - return "root" - } - return n.Addr.String() + " (close)" -} - -func (n *nodeCloseModule) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) { - if !n.Addr.IsRoot() { - return - } - - // If this is the root module, we are cleaning up the walk, so close - // any running provisioners - diags = diags.Append(ctx.CloseProvisioners()) - - switch op { - case walkApply, walkDestroy: - state := ctx.State().Lock() - defer ctx.State().Unlock() - - for modKey, mod := range state.Modules { - // clean out any empty resources - for resKey, res := range mod.Resources { - if len(res.Instances) == 0 { - delete(mod.Resources, resKey) - } - } - - // empty child modules are always removed - if len(mod.Resources) == 0 && !mod.Addr.IsRoot() { - delete(state.Modules, modKey) - } - } - return nil - default: - return nil - } -} - -// nodeValidateModule wraps a nodeExpand module for validation, ensuring that -// no expansion is attempted during evaluation, when count and for_each -// expressions may not be known. -type nodeValidateModule struct { - nodeExpandModule -} - -var _ GraphNodeExecutable = (*nodeValidateModule)(nil) - -// GraphNodeEvalable -func (n *nodeValidateModule) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) { - _, call := n.Addr.Call() - expander := ctx.InstanceExpander() - - // Modules all evaluate to single instances during validation, only to - // create a proper context within which to evaluate. All parent modules - // will be a single instance, but still get our address in the expected - // manner anyway to ensure they've been registered correctly. - for _, module := range expander.ExpandModule(n.Addr.Parent()) { - ctx = ctx.WithPath(module) - - // Validate our for_each and count expressions at a basic level - // We skip validation on known, because there will be unknown values before - // a full expansion, presuming these errors will be caught in later steps - switch { - case n.ModuleCall.Count != nil: - _, countDiags := evaluateCountExpressionValue(n.ModuleCall.Count, ctx) - diags = diags.Append(countDiags) - - case n.ModuleCall.ForEach != nil: - _, forEachDiags := evaluateForEachExpressionValue(n.ModuleCall.ForEach, ctx, true) - diags = diags.Append(forEachDiags) - } - - diags = diags.Append(validateDependsOn(ctx, n.ModuleCall.DependsOn)) - - // now set our own mode to single - expander.SetModuleSingle(module, call) - } - - return diags -} diff --git a/internal/terraform/node_module_expand_test.go b/internal/terraform/node_module_expand_test.go deleted file mode 100644 index 146f754f37c6..000000000000 --- a/internal/terraform/node_module_expand_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package terraform - -import ( - "testing" - - "github.com/hashicorp/hcl/v2/hcltest" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/instances" - "github.com/hashicorp/terraform/internal/states" - "github.com/zclconf/go-cty/cty" -) - -func TestNodeExpandModuleExecute(t *testing.T) { - ctx := &MockEvalContext{ - InstanceExpanderExpander: instances.NewExpander(), - } - ctx.installSimpleEval() - - node := nodeExpandModule{ - Addr: addrs.Module{"child"}, - ModuleCall: &configs.ModuleCall{ - Count: hcltest.MockExprLiteral(cty.NumberIntVal(2)), - }, - } - - err := node.Execute(ctx, walkApply) - if err != nil { - t.Fatalf("unexpected error: %s", err) - } - - if !ctx.InstanceExpanderCalled { - t.Fatal("did not expand") - } -} - -func TestNodeCloseModuleExecute(t *testing.T) { - t.Run("walkApply", func(t *testing.T) { - state := states.NewState() - state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey)) - ctx := &MockEvalContext{ - StateState: state.SyncWrapper(), - } - node := nodeCloseModule{addrs.Module{"child"}} - diags := node.Execute(ctx, walkApply) - if diags.HasErrors() { - t.Fatalf("unexpected error: %s", diags.Err()) - } - - // Since module.child has no resources, it should be removed - if _, ok := state.Modules["module.child"]; !ok { - t.Fatal("module.child should not be removed from state yet") - } - - // the root module should do all the module cleanup - node = nodeCloseModule{addrs.RootModule} - diags = node.Execute(ctx, walkApply) - if diags.HasErrors() { - t.Fatalf("unexpected error: %s", diags.Err()) - } - - // Since module.child has no resources, it should be removed - if _, ok := state.Modules["module.child"]; ok { - t.Fatal("module.child was not removed from state") - } - }) - - // walkImport is a no-op - t.Run("walkImport", func(t *testing.T) { - state := states.NewState() - state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey)) - ctx := &MockEvalContext{ - StateState: state.SyncWrapper(), - } - node := nodeCloseModule{addrs.Module{"child"}} - - diags := node.Execute(ctx, walkImport) - if diags.HasErrors() { - t.Fatalf("unexpected error: %s", diags.Err()) - } - if _, ok := state.Modules["module.child"]; !ok { - t.Fatal("module.child was removed from state, expected no-op") - } - }) -} - -func TestNodeValidateModuleExecute(t *testing.T) { - t.Run("success", func(t *testing.T) { - ctx := &MockEvalContext{ - InstanceExpanderExpander: instances.NewExpander(), - } - ctx.installSimpleEval() - node := nodeValidateModule{ - nodeExpandModule{ - Addr: addrs.Module{"child"}, - ModuleCall: &configs.ModuleCall{ - Count: hcltest.MockExprLiteral(cty.NumberIntVal(2)), - }, - }, - } - - diags := node.Execute(ctx, walkApply) - if diags.HasErrors() { - t.Fatalf("unexpected error: %v", diags.Err()) - } - }) - - t.Run("invalid count", func(t *testing.T) { - ctx := &MockEvalContext{ - InstanceExpanderExpander: instances.NewExpander(), - } - ctx.installSimpleEval() - node := nodeValidateModule{ - nodeExpandModule{ - Addr: addrs.Module{"child"}, - ModuleCall: &configs.ModuleCall{ - Count: hcltest.MockExprLiteral(cty.StringVal("invalid")), - }, - }, - } - - err := node.Execute(ctx, walkApply) - if err == nil { - t.Fatal("expected error, got success") - } - }) - -} diff --git a/internal/terraform/node_module_variable.go b/internal/terraform/node_module_variable.go deleted file mode 100644 index 6d5ae2af89cb..000000000000 --- a/internal/terraform/node_module_variable.go +++ /dev/null @@ -1,244 +0,0 @@ -package terraform - -import ( - "fmt" - "log" - - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/dag" - "github.com/hashicorp/terraform/internal/instances" - "github.com/hashicorp/terraform/internal/lang" - "github.com/hashicorp/terraform/internal/tfdiags" - "github.com/zclconf/go-cty/cty" -) - -// nodeExpandModuleVariable is the placeholder for an variable that has not yet had -// its module path expanded. -type nodeExpandModuleVariable struct { - Addr addrs.InputVariable - Module addrs.Module - Config *configs.Variable - Expr hcl.Expression -} - -var ( - _ GraphNodeDynamicExpandable = (*nodeExpandModuleVariable)(nil) - _ GraphNodeReferenceOutside = (*nodeExpandModuleVariable)(nil) - _ GraphNodeReferenceable = (*nodeExpandModuleVariable)(nil) - _ GraphNodeReferencer = (*nodeExpandModuleVariable)(nil) - _ graphNodeTemporaryValue = (*nodeExpandModuleVariable)(nil) - _ graphNodeExpandsInstances = (*nodeExpandModuleVariable)(nil) -) - -func (n *nodeExpandModuleVariable) expandsInstances() {} - -func (n *nodeExpandModuleVariable) temporaryValue() bool { - return true -} - -func (n *nodeExpandModuleVariable) DynamicExpand(ctx EvalContext) (*Graph, error) { - var g Graph - expander := ctx.InstanceExpander() - for _, module := range expander.ExpandModule(n.Module) { - o := &nodeModuleVariable{ - Addr: n.Addr.Absolute(module), - Config: n.Config, - Expr: n.Expr, - ModuleInstance: module, - } - g.Add(o) - } - addRootNodeToGraph(&g) - return &g, nil -} - -func (n *nodeExpandModuleVariable) Name() string { - return fmt.Sprintf("%s.%s (expand)", n.Module, n.Addr.String()) -} - -// GraphNodeModulePath -func (n *nodeExpandModuleVariable) ModulePath() addrs.Module { - return n.Module -} - -// GraphNodeReferencer -func (n *nodeExpandModuleVariable) References() []*addrs.Reference { - - // If we have no value expression, we cannot depend on anything. - if n.Expr == nil { - return nil - } - - // Variables in the root don't depend on anything, because their values - // are gathered prior to the graph walk and recorded in the context. - if len(n.Module) == 0 { - return nil - } - - // Otherwise, we depend on anything referenced by our value expression. - // We ignore diagnostics here under the assumption that we'll re-eval - // all these things later and catch them then; for our purposes here, - // we only care about valid references. - // - // Due to our GraphNodeReferenceOutside implementation, the addresses - // returned by this function are interpreted in the _parent_ module from - // where our associated variable was declared, which is correct because - // our value expression is assigned within a "module" block in the parent - // module. - refs, _ := lang.ReferencesInExpr(n.Expr) - return refs -} - -// GraphNodeReferenceOutside implementation -func (n *nodeExpandModuleVariable) ReferenceOutside() (selfPath, referencePath addrs.Module) { - return n.Module, n.Module.Parent() -} - -// GraphNodeReferenceable -func (n *nodeExpandModuleVariable) ReferenceableAddrs() []addrs.Referenceable { - return []addrs.Referenceable{n.Addr} -} - -// nodeModuleVariable represents a module variable input during -// the apply step. -type nodeModuleVariable struct { - Addr addrs.AbsInputVariableInstance - Config *configs.Variable // Config is the var in the config - Expr hcl.Expression // Expr is the value expression given in the call - // ModuleInstance in order to create the appropriate context for evaluating - // ModuleCallArguments, ex. so count.index and each.key can resolve - ModuleInstance addrs.ModuleInstance -} - -// Ensure that we are implementing all of the interfaces we think we are -// implementing. -var ( - _ GraphNodeModuleInstance = (*nodeModuleVariable)(nil) - _ GraphNodeExecutable = (*nodeModuleVariable)(nil) - _ graphNodeTemporaryValue = (*nodeModuleVariable)(nil) - _ dag.GraphNodeDotter = (*nodeModuleVariable)(nil) -) - -func (n *nodeModuleVariable) temporaryValue() bool { - return true -} - -func (n *nodeModuleVariable) Name() string { - return n.Addr.String() -} - -// GraphNodeModuleInstance -func (n *nodeModuleVariable) Path() addrs.ModuleInstance { - // We execute in the parent scope (above our own module) because - // expressions in our value are resolved in that context. - return n.Addr.Module.Parent() -} - -// GraphNodeModulePath -func (n *nodeModuleVariable) ModulePath() addrs.Module { - return n.Addr.Module.Module() -} - -// GraphNodeExecutable -func (n *nodeModuleVariable) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) { - log.Printf("[TRACE] nodeModuleVariable: evaluating %s", n.Addr) - - var val cty.Value - var err error - - switch op { - case walkValidate: - val, err = n.evalModuleVariable(ctx, true) - diags = diags.Append(err) - default: - val, err = n.evalModuleVariable(ctx, false) - diags = diags.Append(err) - } - if diags.HasErrors() { - return diags - } - - // Set values for arguments of a child module call, for later retrieval - // during expression evaluation. - _, call := n.Addr.Module.CallInstance() - ctx.SetModuleCallArgument(call, n.Addr.Variable, val) - - return evalVariableValidations(n.Addr, n.Config, n.Expr, ctx) -} - -// dag.GraphNodeDotter impl. -func (n *nodeModuleVariable) DotNode(name string, opts *dag.DotOpts) *dag.DotNode { - return &dag.DotNode{ - Name: name, - Attrs: map[string]string{ - "label": n.Name(), - "shape": "note", - }, - } -} - -// evalModuleVariable produces the value for a particular variable as will -// be used by a child module instance. -// -// The result is written into a map, with its key set to the local name of the -// variable, disregarding the module instance address. A map is returned instead -// of a single value as a result of trying to be convenient for use with -// EvalContext.SetModuleCallArguments, which expects a map to merge in with any -// existing arguments. -// -// validateOnly indicates that this evaluation is only for config -// validation, and we will not have any expansion module instance -// repetition data. -func (n *nodeModuleVariable) evalModuleVariable(ctx EvalContext, validateOnly bool) (cty.Value, error) { - var diags tfdiags.Diagnostics - var givenVal cty.Value - var errSourceRange tfdiags.SourceRange - if expr := n.Expr; expr != nil { - var moduleInstanceRepetitionData instances.RepetitionData - - switch { - case validateOnly: - // the instance expander does not track unknown expansion values, so we - // have to assume all RepetitionData is unknown. - moduleInstanceRepetitionData = instances.RepetitionData{ - CountIndex: cty.UnknownVal(cty.Number), - EachKey: cty.UnknownVal(cty.String), - EachValue: cty.DynamicVal, - } - - default: - // Get the repetition data for this module instance, - // so we can create the appropriate scope for evaluating our expression - moduleInstanceRepetitionData = ctx.InstanceExpander().GetModuleInstanceRepetitionData(n.ModuleInstance) - } - - scope := ctx.EvaluationScope(nil, moduleInstanceRepetitionData) - val, moreDiags := scope.EvalExpr(expr, cty.DynamicPseudoType) - diags = diags.Append(moreDiags) - if moreDiags.HasErrors() { - return cty.DynamicVal, diags.ErrWithWarnings() - } - givenVal = val - errSourceRange = tfdiags.SourceRangeFromHCL(expr.Range()) - } else { - // We'll use cty.NilVal to represent the variable not being set at all. - givenVal = cty.NilVal - errSourceRange = tfdiags.SourceRangeFromHCL(n.Config.DeclRange) // we use the declaration range as a fallback for an undefined variable - } - - // We construct a synthetic InputValue here to pretend as if this were - // a root module variable set from outside, just as a convenience so we - // can reuse the InputValue type for this. - rawVal := &InputValue{ - Value: givenVal, - SourceType: ValueFromConfig, - SourceRange: errSourceRange, - } - - finalVal, moreDiags := prepareFinalInputVariableValue(n.Addr, rawVal, n.Config) - diags = diags.Append(moreDiags) - - return finalVal, diags.ErrWithWarnings() -} diff --git a/internal/terraform/node_module_variable_test.go b/internal/terraform/node_module_variable_test.go deleted file mode 100644 index e2b458cdbbbe..000000000000 --- a/internal/terraform/node_module_variable_test.go +++ /dev/null @@ -1,121 +0,0 @@ -package terraform - -import ( - "reflect" - "testing" - - "github.com/go-test/deep" - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/zclconf/go-cty/cty" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" -) - -func TestNodeModuleVariablePath(t *testing.T) { - n := &nodeModuleVariable{ - Addr: addrs.RootModuleInstance.InputVariable("foo"), - Config: &configs.Variable{ - Name: "foo", - Type: cty.String, - ConstraintType: cty.String, - }, - } - - want := addrs.RootModuleInstance - got := n.Path() - if got.String() != want.String() { - t.Fatalf("wrong module address %s; want %s", got, want) - } -} - -func TestNodeModuleVariableReferenceableName(t *testing.T) { - n := &nodeExpandModuleVariable{ - Addr: addrs.InputVariable{Name: "foo"}, - Config: &configs.Variable{ - Name: "foo", - Type: cty.String, - ConstraintType: cty.String, - }, - } - - { - expected := []addrs.Referenceable{ - addrs.InputVariable{Name: "foo"}, - } - actual := n.ReferenceableAddrs() - if !reflect.DeepEqual(actual, expected) { - t.Fatalf("%#v != %#v", actual, expected) - } - } - - { - gotSelfPath, gotReferencePath := n.ReferenceOutside() - wantSelfPath := addrs.RootModuleInstance - wantReferencePath := addrs.RootModuleInstance - if got, want := gotSelfPath.String(), wantSelfPath.String(); got != want { - t.Errorf("wrong self path\ngot: %s\nwant: %s", got, want) - } - if got, want := gotReferencePath.String(), wantReferencePath.String(); got != want { - t.Errorf("wrong reference path\ngot: %s\nwant: %s", got, want) - } - } - -} - -func TestNodeModuleVariableReference(t *testing.T) { - n := &nodeExpandModuleVariable{ - Addr: addrs.InputVariable{Name: "foo"}, - Module: addrs.RootModule.Child("bar"), - Config: &configs.Variable{ - Name: "foo", - Type: cty.String, - ConstraintType: cty.String, - }, - Expr: &hclsyntax.ScopeTraversalExpr{ - Traversal: hcl.Traversal{ - hcl.TraverseRoot{Name: "var"}, - hcl.TraverseAttr{Name: "foo"}, - }, - }, - } - - want := []*addrs.Reference{ - { - Subject: addrs.InputVariable{Name: "foo"}, - }, - } - got := n.References() - for _, problem := range deep.Equal(got, want) { - t.Error(problem) - } -} - -func TestNodeModuleVariableReference_grandchild(t *testing.T) { - n := &nodeExpandModuleVariable{ - Addr: addrs.InputVariable{Name: "foo"}, - Module: addrs.RootModule.Child("bar"), - Config: &configs.Variable{ - Name: "foo", - Type: cty.String, - ConstraintType: cty.String, - }, - Expr: &hclsyntax.ScopeTraversalExpr{ - Traversal: hcl.Traversal{ - hcl.TraverseRoot{Name: "var"}, - hcl.TraverseAttr{Name: "foo"}, - }, - }, - } - - want := []*addrs.Reference{ - { - Subject: addrs.InputVariable{Name: "foo"}, - }, - } - got := n.References() - for _, problem := range deep.Equal(got, want) { - t.Error(problem) - } -} diff --git a/internal/terraform/node_output.go b/internal/terraform/node_output.go deleted file mode 100644 index 5b3a707d2489..000000000000 --- a/internal/terraform/node_output.go +++ /dev/null @@ -1,610 +0,0 @@ -package terraform - -import ( - "fmt" - "log" - - "github.com/hashicorp/hcl/v2" - "github.com/zclconf/go-cty/cty" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/dag" - "github.com/hashicorp/terraform/internal/lang" - "github.com/hashicorp/terraform/internal/lang/marks" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -// nodeExpandOutput is the placeholder for a non-root module output that has -// not yet had its module path expanded. -type nodeExpandOutput struct { - Addr addrs.OutputValue - Module addrs.Module - Config *configs.Output - PlanDestroy bool - ApplyDestroy bool - RefreshOnly bool - - // Planning is set to true when this node is in a graph that was produced - // by the plan graph builder, as opposed to the apply graph builder. - // This quirk is just because we share the same node type between both - // phases but in practice there are a few small differences in the actions - // we need to take between plan and apply. See method DynamicExpand for - // details. - Planning bool -} - -var ( - _ GraphNodeReferenceable = (*nodeExpandOutput)(nil) - _ GraphNodeReferencer = (*nodeExpandOutput)(nil) - _ GraphNodeReferenceOutside = (*nodeExpandOutput)(nil) - _ GraphNodeDynamicExpandable = (*nodeExpandOutput)(nil) - _ graphNodeTemporaryValue = (*nodeExpandOutput)(nil) - _ graphNodeExpandsInstances = (*nodeExpandOutput)(nil) -) - -func (n *nodeExpandOutput) expandsInstances() {} - -func (n *nodeExpandOutput) temporaryValue() bool { - // non root outputs are temporary - return !n.Module.IsRoot() -} - -func (n *nodeExpandOutput) DynamicExpand(ctx EvalContext) (*Graph, error) { - expander := ctx.InstanceExpander() - changes := ctx.Changes() - - // If this is an output value that participates in custom condition checks - // (i.e. it has preconditions or postconditions) then the check state - // wants to know the addresses of the checkable objects so that it can - // treat them as unknown status if we encounter an error before actually - // visiting the checks. - // - // We must do this only during planning, because the apply phase will start - // with all of the same checkable objects that were registered during the - // planning phase. Consumers of our JSON plan and state formats expect - // that the set of checkable objects will be consistent between the plan - // and any state snapshots created during apply, and that only the statuses - // of those objects will have changed. - var checkableAddrs addrs.Set[addrs.Checkable] - if n.Planning { - if checkState := ctx.Checks(); checkState.ConfigHasChecks(n.Addr.InModule(n.Module)) { - checkableAddrs = addrs.MakeSet[addrs.Checkable]() - } - } - - var g Graph - for _, module := range expander.ExpandModule(n.Module) { - absAddr := n.Addr.Absolute(module) - if checkableAddrs != nil { - checkableAddrs.Add(absAddr) - } - - // Find any recorded change for this output - var change *plans.OutputChangeSrc - var outputChanges []*plans.OutputChangeSrc - if module.IsRoot() { - outputChanges = changes.GetRootOutputChanges() - } else { - parent, call := module.Call() - outputChanges = changes.GetOutputChanges(parent, call) - } - for _, c := range outputChanges { - if c.Addr.String() == absAddr.String() { - change = c - break - } - } - - var node dag.Vertex - switch { - case module.IsRoot() && (n.PlanDestroy || n.ApplyDestroy): - node = &NodeDestroyableOutput{ - Addr: absAddr, - Planning: n.Planning, - } - - case n.PlanDestroy: - // nothing is done here for non-root outputs - continue - - default: - node = &NodeApplyableOutput{ - Addr: absAddr, - Config: n.Config, - Change: change, - RefreshOnly: n.RefreshOnly, - DestroyApply: n.ApplyDestroy, - Planning: n.Planning, - } - } - - log.Printf("[TRACE] Expanding output: adding %s as %T", absAddr.String(), node) - g.Add(node) - } - addRootNodeToGraph(&g) - - if checkableAddrs != nil { - checkState := ctx.Checks() - checkState.ReportCheckableObjects(n.Addr.InModule(n.Module), checkableAddrs) - } - - return &g, nil -} - -func (n *nodeExpandOutput) Name() string { - path := n.Module.String() - addr := n.Addr.String() + " (expand)" - if path != "" { - return path + "." + addr - } - return addr -} - -// GraphNodeModulePath -func (n *nodeExpandOutput) ModulePath() addrs.Module { - return n.Module -} - -// GraphNodeReferenceable -func (n *nodeExpandOutput) ReferenceableAddrs() []addrs.Referenceable { - // An output in the root module can't be referenced at all. - if n.Module.IsRoot() { - return nil - } - - // the output is referenced through the module call, and via the - // module itself. - _, call := n.Module.Call() - callOutput := addrs.ModuleCallOutput{ - Call: call, - Name: n.Addr.Name, - } - - // Otherwise, we can reference the output via the - // module call itself - return []addrs.Referenceable{call, callOutput} -} - -// GraphNodeReferenceOutside implementation -func (n *nodeExpandOutput) ReferenceOutside() (selfPath, referencePath addrs.Module) { - // Output values have their expressions resolved in the context of the - // module where they are defined. - referencePath = n.Module - - // ...but they are referenced in the context of their calling module. - selfPath = referencePath.Parent() - - return // uses named return values -} - -// GraphNodeReferencer -func (n *nodeExpandOutput) References() []*addrs.Reference { - // DestroyNodes do not reference anything. - if n.Module.IsRoot() && n.ApplyDestroy { - return nil - } - - return referencesForOutput(n.Config) -} - -// NodeApplyableOutput represents an output that is "applyable": -// it is ready to be applied. -type NodeApplyableOutput struct { - Addr addrs.AbsOutputValue - Config *configs.Output // Config is the output in the config - // If this is being evaluated during apply, we may have a change recorded already - Change *plans.OutputChangeSrc - - // Refresh-only mode means that any failing output preconditions are - // reported as warnings rather than errors - RefreshOnly bool - - // DestroyApply indicates that we are applying a destroy plan, and do not - // need to account for conditional blocks. - DestroyApply bool - - Planning bool -} - -var ( - _ GraphNodeModuleInstance = (*NodeApplyableOutput)(nil) - _ GraphNodeReferenceable = (*NodeApplyableOutput)(nil) - _ GraphNodeReferencer = (*NodeApplyableOutput)(nil) - _ GraphNodeReferenceOutside = (*NodeApplyableOutput)(nil) - _ GraphNodeExecutable = (*NodeApplyableOutput)(nil) - _ graphNodeTemporaryValue = (*NodeApplyableOutput)(nil) - _ dag.GraphNodeDotter = (*NodeApplyableOutput)(nil) -) - -func (n *NodeApplyableOutput) temporaryValue() bool { - // this must always be evaluated if it is a root module output - return !n.Addr.Module.IsRoot() -} - -func (n *NodeApplyableOutput) Name() string { - return n.Addr.String() -} - -// GraphNodeModuleInstance -func (n *NodeApplyableOutput) Path() addrs.ModuleInstance { - return n.Addr.Module -} - -// GraphNodeModulePath -func (n *NodeApplyableOutput) ModulePath() addrs.Module { - return n.Addr.Module.Module() -} - -func referenceOutsideForOutput(addr addrs.AbsOutputValue) (selfPath, referencePath addrs.Module) { - // Output values have their expressions resolved in the context of the - // module where they are defined. - referencePath = addr.Module.Module() - - // ...but they are referenced in the context of their calling module. - selfPath = addr.Module.Parent().Module() - - return // uses named return values -} - -// GraphNodeReferenceOutside implementation -func (n *NodeApplyableOutput) ReferenceOutside() (selfPath, referencePath addrs.Module) { - return referenceOutsideForOutput(n.Addr) -} - -func referenceableAddrsForOutput(addr addrs.AbsOutputValue) []addrs.Referenceable { - // An output in the root module can't be referenced at all. - if addr.Module.IsRoot() { - return nil - } - - // Otherwise, we can be referenced via a reference to our output name - // on the parent module's call, or via a reference to the entire call. - // e.g. module.foo.bar or just module.foo . - // Note that our ReferenceOutside method causes these addresses to be - // relative to the calling module, not the module where the output - // was declared. - _, outp := addr.ModuleCallOutput() - _, call := addr.Module.CallInstance() - - return []addrs.Referenceable{outp, call} -} - -// GraphNodeReferenceable -func (n *NodeApplyableOutput) ReferenceableAddrs() []addrs.Referenceable { - return referenceableAddrsForOutput(n.Addr) -} - -func referencesForOutput(c *configs.Output) []*addrs.Reference { - var refs []*addrs.Reference - - impRefs, _ := lang.ReferencesInExpr(c.Expr) - expRefs, _ := lang.References(c.DependsOn) - - refs = append(refs, impRefs...) - refs = append(refs, expRefs...) - - for _, check := range c.Preconditions { - condRefs, _ := lang.ReferencesInExpr(check.Condition) - refs = append(refs, condRefs...) - errRefs, _ := lang.ReferencesInExpr(check.ErrorMessage) - refs = append(refs, errRefs...) - } - - return refs -} - -// GraphNodeReferencer -func (n *NodeApplyableOutput) References() []*addrs.Reference { - return referencesForOutput(n.Config) -} - -// GraphNodeExecutable -func (n *NodeApplyableOutput) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) { - state := ctx.State() - if state == nil { - return - } - - changes := ctx.Changes() // may be nil, if we're not working on a changeset - - val := cty.UnknownVal(cty.DynamicPseudoType) - changeRecorded := n.Change != nil - // we we have a change recorded, we don't need to re-evaluate if the value - // was known - if changeRecorded { - change, err := n.Change.Decode() - diags = diags.Append(err) - if err == nil { - val = change.After - } - } - - // Checks are not evaluated during a destroy. The checks may fail, may not - // be valid, or may not have been registered at all. - if !n.DestroyApply { - checkRuleSeverity := tfdiags.Error - if n.RefreshOnly { - checkRuleSeverity = tfdiags.Warning - } - checkDiags := evalCheckRules( - addrs.OutputPrecondition, - n.Config.Preconditions, - ctx, n.Addr, EvalDataForNoInstanceKey, - checkRuleSeverity, - ) - diags = diags.Append(checkDiags) - if diags.HasErrors() { - return diags // failed preconditions prevent further evaluation - } - } - - // If there was no change recorded, or the recorded change was not wholly - // known, then we need to re-evaluate the output - if !changeRecorded || !val.IsWhollyKnown() { - // This has to run before we have a state lock, since evaluation also - // reads the state - var evalDiags tfdiags.Diagnostics - val, evalDiags = ctx.EvaluateExpr(n.Config.Expr, cty.DynamicPseudoType, nil) - diags = diags.Append(evalDiags) - - // We'll handle errors below, after we have loaded the module. - // Outputs don't have a separate mode for validation, so validate - // depends_on expressions here too - diags = diags.Append(validateDependsOn(ctx, n.Config.DependsOn)) - - // For root module outputs in particular, an output value must be - // statically declared as sensitive in order to dynamically return - // a sensitive result, to help avoid accidental exposure in the state - // of a sensitive value that the user doesn't want to include there. - if n.Addr.Module.IsRoot() { - if !n.Config.Sensitive && marks.Contains(val, marks.Sensitive) { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Output refers to sensitive values", - Detail: `To reduce the risk of accidentally exporting sensitive data that was intended to be only internal, Terraform requires that any root module output containing sensitive data be explicitly marked as sensitive, to confirm your intent. - -If you do intend to export this data, annotate the output value as sensitive by adding the following argument: - sensitive = true`, - Subject: n.Config.DeclRange.Ptr(), - }) - } - } - } - - // handling the interpolation error - if diags.HasErrors() { - if flagWarnOutputErrors { - log.Printf("[ERROR] Output interpolation %q failed: %s", n.Addr, diags.Err()) - // if we're continuing, make sure the output is included, and - // marked as unknown. If the evaluator was able to find a type - // for the value in spite of the error then we'll use it. - n.setValue(state, changes, cty.UnknownVal(val.Type())) - - // Keep existing warnings, while converting errors to warnings. - // This is not meant to be the normal path, so there no need to - // make the errors pretty. - var warnings tfdiags.Diagnostics - for _, d := range diags { - switch d.Severity() { - case tfdiags.Warning: - warnings = warnings.Append(d) - case tfdiags.Error: - desc := d.Description() - warnings = warnings.Append(tfdiags.SimpleWarning(fmt.Sprintf("%s:%s", desc.Summary, desc.Detail))) - } - } - - return warnings - } - return diags - } - n.setValue(state, changes, val) - - // If we were able to evaluate a new value, we can update that in the - // refreshed state as well. - if state = ctx.RefreshState(); state != nil && val.IsWhollyKnown() { - // we only need to update the state, do not pass in the changes again - n.setValue(state, nil, val) - } - - return diags -} - -// dag.GraphNodeDotter impl. -func (n *NodeApplyableOutput) DotNode(name string, opts *dag.DotOpts) *dag.DotNode { - return &dag.DotNode{ - Name: name, - Attrs: map[string]string{ - "label": n.Name(), - "shape": "note", - }, - } -} - -// NodeDestroyableOutput represents an output that is "destroyable": -// its application will remove the output from the state. -type NodeDestroyableOutput struct { - Addr addrs.AbsOutputValue - Planning bool -} - -var ( - _ GraphNodeExecutable = (*NodeDestroyableOutput)(nil) - _ dag.GraphNodeDotter = (*NodeDestroyableOutput)(nil) -) - -func (n *NodeDestroyableOutput) Name() string { - return fmt.Sprintf("%s (destroy)", n.Addr.String()) -} - -// GraphNodeModulePath -func (n *NodeDestroyableOutput) ModulePath() addrs.Module { - return n.Addr.Module.Module() -} - -func (n *NodeDestroyableOutput) temporaryValue() bool { - // this must always be evaluated if it is a root module output - return !n.Addr.Module.IsRoot() -} - -// GraphNodeExecutable -func (n *NodeDestroyableOutput) Execute(ctx EvalContext, op walkOperation) tfdiags.Diagnostics { - state := ctx.State() - if state == nil { - return nil - } - - // if this is a root module, try to get a before value from the state for - // the diff - sensitiveBefore := false - before := cty.NullVal(cty.DynamicPseudoType) - mod := state.Module(n.Addr.Module) - if n.Addr.Module.IsRoot() && mod != nil { - if o, ok := mod.OutputValues[n.Addr.OutputValue.Name]; ok { - sensitiveBefore = o.Sensitive - before = o.Value - } else { - // If the output was not in state, a delete change would - // be meaningless, so exit early. - return nil - - } - } - - changes := ctx.Changes() - if changes != nil && n.Planning { - change := &plans.OutputChange{ - Addr: n.Addr, - Sensitive: sensitiveBefore, - Change: plans.Change{ - Action: plans.Delete, - Before: before, - After: cty.NullVal(cty.DynamicPseudoType), - }, - } - - cs, err := change.Encode() - if err != nil { - // Should never happen, since we just constructed this right above - panic(fmt.Sprintf("planned change for %s could not be encoded: %s", n.Addr, err)) - } - log.Printf("[TRACE] NodeDestroyableOutput: Saving %s change for %s in changeset", change.Action, n.Addr) - - changes.RemoveOutputChange(n.Addr) // remove any existing planned change, if present - changes.AppendOutputChange(cs) // add the new planned change - } - - state.RemoveOutputValue(n.Addr) - return nil -} - -// dag.GraphNodeDotter impl. -func (n *NodeDestroyableOutput) DotNode(name string, opts *dag.DotOpts) *dag.DotNode { - return &dag.DotNode{ - Name: name, - Attrs: map[string]string{ - "label": n.Name(), - "shape": "note", - }, - } -} - -func (n *NodeApplyableOutput) setValue(state *states.SyncState, changes *plans.ChangesSync, val cty.Value) { - if changes != nil && n.Planning { - // if this is a root module, try to get a before value from the state for - // the diff - sensitiveBefore := false - before := cty.NullVal(cty.DynamicPseudoType) - - // is this output new to our state? - newOutput := true - - mod := state.Module(n.Addr.Module) - if n.Addr.Module.IsRoot() && mod != nil { - for name, o := range mod.OutputValues { - if name == n.Addr.OutputValue.Name { - before = o.Value - sensitiveBefore = o.Sensitive - newOutput = false - break - } - } - } - - // We will not show the value if either the before or after are marked - // as sensitive. We can show the value again once sensitivity is - // removed from both the config and the state. - sensitiveChange := sensitiveBefore || n.Config.Sensitive - - // strip any marks here just to be sure we don't panic on the True comparison - unmarkedVal, _ := val.UnmarkDeep() - - action := plans.Update - switch { - case val.IsNull() && before.IsNull(): - // This is separate from the NoOp case below, since we can ignore - // sensitivity here when there are only null values. - action = plans.NoOp - - case newOutput: - // This output was just added to the configuration - action = plans.Create - - case val.IsWhollyKnown() && - unmarkedVal.Equals(before).True() && - n.Config.Sensitive == sensitiveBefore: - // Sensitivity must also match to be a NoOp. - // Theoretically marks may not match here, but sensitivity is the - // only one we can act on, and the state will have been loaded - // without any marks to consider. - action = plans.NoOp - } - - change := &plans.OutputChange{ - Addr: n.Addr, - Sensitive: sensitiveChange, - Change: plans.Change{ - Action: action, - Before: before, - After: val, - }, - } - - cs, err := change.Encode() - if err != nil { - // Should never happen, since we just constructed this right above - panic(fmt.Sprintf("planned change for %s could not be encoded: %s", n.Addr, err)) - } - log.Printf("[TRACE] setValue: Saving %s change for %s in changeset", change.Action, n.Addr) - changes.AppendOutputChange(cs) // add the new planned change - } - - if changes != nil && !n.Planning { - // During apply there is no longer any change to track, so we must - // ensure the state is updated and not overridden by a change. - changes.RemoveOutputChange(n.Addr) - } - - // Null outputs must be saved for modules so that they can still be - // evaluated. Null root outputs are removed entirely, which is always fine - // because they can't be referenced by anything else in the configuration. - if n.Addr.Module.IsRoot() && val.IsNull() { - log.Printf("[TRACE] setValue: Removing %s from state (it is now null)", n.Addr) - state.RemoveOutputValue(n.Addr) - return - } - - log.Printf("[TRACE] setValue: Saving value for %s in state", n.Addr) - - // non-root outputs need to keep sensitive marks for evaluation, but are - // not serialized. - if n.Addr.Module.IsRoot() { - val, _ = val.UnmarkDeep() - val = cty.UnknownAsNull(val) - } - - state.SetOutputValue(n.Addr, val, n.Config.Sensitive) -} diff --git a/internal/terraform/node_output_test.go b/internal/terraform/node_output_test.go deleted file mode 100644 index 80d60539e83c..000000000000 --- a/internal/terraform/node_output_test.go +++ /dev/null @@ -1,187 +0,0 @@ -package terraform - -import ( - "strings" - "testing" - - "github.com/hashicorp/hcl/v2" - "github.com/zclconf/go-cty/cty" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/checks" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/lang/marks" - "github.com/hashicorp/terraform/internal/states" -) - -func TestNodeApplyableOutputExecute_knownValue(t *testing.T) { - ctx := new(MockEvalContext) - ctx.StateState = states.NewState().SyncWrapper() - ctx.RefreshStateState = states.NewState().SyncWrapper() - ctx.ChecksState = checks.NewState(nil) - - config := &configs.Output{Name: "map-output"} - addr := addrs.OutputValue{Name: config.Name}.Absolute(addrs.RootModuleInstance) - node := &NodeApplyableOutput{Config: config, Addr: addr} - val := cty.MapVal(map[string]cty.Value{ - "a": cty.StringVal("b"), - }) - ctx.EvaluateExprResult = val - - err := node.Execute(ctx, walkApply) - if err != nil { - t.Fatalf("unexpected execute error: %s", err) - } - - outputVal := ctx.StateState.OutputValue(addr) - if got, want := outputVal.Value, val; !got.RawEquals(want) { - t.Errorf("wrong output value in state\n got: %#v\nwant: %#v", got, want) - } - - if !ctx.RefreshStateCalled { - t.Fatal("should have called RefreshState, but didn't") - } - refreshOutputVal := ctx.RefreshStateState.OutputValue(addr) - if got, want := refreshOutputVal.Value, val; !got.RawEquals(want) { - t.Fatalf("wrong output value in refresh state\n got: %#v\nwant: %#v", got, want) - } -} - -func TestNodeApplyableOutputExecute_noState(t *testing.T) { - ctx := new(MockEvalContext) - - config := &configs.Output{Name: "map-output"} - addr := addrs.OutputValue{Name: config.Name}.Absolute(addrs.RootModuleInstance) - node := &NodeApplyableOutput{Config: config, Addr: addr} - val := cty.MapVal(map[string]cty.Value{ - "a": cty.StringVal("b"), - }) - ctx.EvaluateExprResult = val - - err := node.Execute(ctx, walkApply) - if err != nil { - t.Fatalf("unexpected execute error: %s", err) - } -} - -func TestNodeApplyableOutputExecute_invalidDependsOn(t *testing.T) { - ctx := new(MockEvalContext) - ctx.StateState = states.NewState().SyncWrapper() - ctx.ChecksState = checks.NewState(nil) - - config := &configs.Output{ - Name: "map-output", - DependsOn: []hcl.Traversal{ - { - hcl.TraverseRoot{Name: "test_instance"}, - hcl.TraverseAttr{Name: "foo"}, - hcl.TraverseAttr{Name: "bar"}, - }, - }, - } - addr := addrs.OutputValue{Name: config.Name}.Absolute(addrs.RootModuleInstance) - node := &NodeApplyableOutput{Config: config, Addr: addr} - val := cty.MapVal(map[string]cty.Value{ - "a": cty.StringVal("b"), - }) - ctx.EvaluateExprResult = val - - diags := node.Execute(ctx, walkApply) - if !diags.HasErrors() { - t.Fatal("expected execute error, but there was none") - } - if got, want := diags.Err().Error(), "Invalid depends_on reference"; !strings.Contains(got, want) { - t.Errorf("expected error to include %q, but was: %s", want, got) - } -} - -func TestNodeApplyableOutputExecute_sensitiveValueNotOutput(t *testing.T) { - ctx := new(MockEvalContext) - ctx.StateState = states.NewState().SyncWrapper() - ctx.ChecksState = checks.NewState(nil) - - config := &configs.Output{Name: "map-output"} - addr := addrs.OutputValue{Name: config.Name}.Absolute(addrs.RootModuleInstance) - node := &NodeApplyableOutput{Config: config, Addr: addr} - val := cty.MapVal(map[string]cty.Value{ - "a": cty.StringVal("b").Mark(marks.Sensitive), - }) - ctx.EvaluateExprResult = val - - diags := node.Execute(ctx, walkApply) - if !diags.HasErrors() { - t.Fatal("expected execute error, but there was none") - } - if got, want := diags.Err().Error(), "Output refers to sensitive values"; !strings.Contains(got, want) { - t.Errorf("expected error to include %q, but was: %s", want, got) - } -} - -func TestNodeApplyableOutputExecute_sensitiveValueAndOutput(t *testing.T) { - ctx := new(MockEvalContext) - ctx.StateState = states.NewState().SyncWrapper() - ctx.ChecksState = checks.NewState(nil) - - config := &configs.Output{ - Name: "map-output", - Sensitive: true, - } - addr := addrs.OutputValue{Name: config.Name}.Absolute(addrs.RootModuleInstance) - node := &NodeApplyableOutput{Config: config, Addr: addr} - val := cty.MapVal(map[string]cty.Value{ - "a": cty.StringVal("b").Mark(marks.Sensitive), - }) - ctx.EvaluateExprResult = val - - err := node.Execute(ctx, walkApply) - if err != nil { - t.Fatalf("unexpected execute error: %s", err) - } - - // Unmarked value should be stored in state - outputVal := ctx.StateState.OutputValue(addr) - want, _ := val.UnmarkDeep() - if got := outputVal.Value; !got.RawEquals(want) { - t.Errorf("wrong output value in state\n got: %#v\nwant: %#v", got, want) - } -} - -func TestNodeDestroyableOutputExecute(t *testing.T) { - outputAddr := addrs.OutputValue{Name: "foo"}.Absolute(addrs.RootModuleInstance) - - state := states.NewState() - state.Module(addrs.RootModuleInstance).SetOutputValue("foo", cty.StringVal("bar"), false) - state.OutputValue(outputAddr) - - ctx := &MockEvalContext{ - StateState: state.SyncWrapper(), - } - node := NodeDestroyableOutput{Addr: outputAddr} - - diags := node.Execute(ctx, walkApply) - if diags.HasErrors() { - t.Fatalf("Unexpected error: %s", diags.Err()) - } - if state.OutputValue(outputAddr) != nil { - t.Fatal("Unexpected outputs in state after removal") - } -} - -func TestNodeDestroyableOutputExecute_notInState(t *testing.T) { - outputAddr := addrs.OutputValue{Name: "foo"}.Absolute(addrs.RootModuleInstance) - - state := states.NewState() - - ctx := &MockEvalContext{ - StateState: state.SyncWrapper(), - } - node := NodeDestroyableOutput{Addr: outputAddr} - - diags := node.Execute(ctx, walkApply) - if diags.HasErrors() { - t.Fatalf("Unexpected error: %s", diags.Err()) - } - if state.OutputValue(outputAddr) != nil { - t.Fatal("Unexpected outputs in state after removal") - } -} diff --git a/internal/terraform/node_provider.go b/internal/terraform/node_provider.go deleted file mode 100644 index c5b09136cb28..000000000000 --- a/internal/terraform/node_provider.go +++ /dev/null @@ -1,179 +0,0 @@ -package terraform - -import ( - "fmt" - "log" - - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/tfdiags" - "github.com/zclconf/go-cty/cty" -) - -// NodeApplyableProvider represents a provider during an apply. -type NodeApplyableProvider struct { - *NodeAbstractProvider -} - -var ( - _ GraphNodeExecutable = (*NodeApplyableProvider)(nil) -) - -// GraphNodeExecutable -func (n *NodeApplyableProvider) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) { - _, err := ctx.InitProvider(n.Addr) - diags = diags.Append(err) - if diags.HasErrors() { - return diags - } - provider, _, err := getProvider(ctx, n.Addr) - diags = diags.Append(err) - if diags.HasErrors() { - return diags - } - - switch op { - case walkValidate: - log.Printf("[TRACE] NodeApplyableProvider: validating configuration for %s", n.Addr) - return diags.Append(n.ValidateProvider(ctx, provider)) - case walkPlan, walkPlanDestroy, walkApply, walkDestroy: - log.Printf("[TRACE] NodeApplyableProvider: configuring %s", n.Addr) - return diags.Append(n.ConfigureProvider(ctx, provider, false)) - case walkImport: - log.Printf("[TRACE] NodeApplyableProvider: configuring %s (requiring that configuration is wholly known)", n.Addr) - return diags.Append(n.ConfigureProvider(ctx, provider, true)) - } - return diags -} - -func (n *NodeApplyableProvider) ValidateProvider(ctx EvalContext, provider providers.Interface) (diags tfdiags.Diagnostics) { - - configBody := buildProviderConfig(ctx, n.Addr, n.ProviderConfig()) - - // if a provider config is empty (only an alias), return early and don't continue - // validation. validate doesn't need to fully configure the provider itself, so - // skipping a provider with an implied configuration won't prevent other validation from completing. - _, noConfigDiags := configBody.Content(&hcl.BodySchema{}) - if !noConfigDiags.HasErrors() { - return nil - } - - schemaResp := provider.GetProviderSchema() - diags = diags.Append(schemaResp.Diagnostics.InConfigBody(configBody, n.Addr.String())) - if diags.HasErrors() { - return diags - } - - configSchema := schemaResp.Provider.Block - if configSchema == nil { - // Should never happen in real code, but often comes up in tests where - // mock schemas are being used that tend to be incomplete. - log.Printf("[WARN] ValidateProvider: no config schema is available for %s, so using empty schema", n.Addr) - configSchema = &configschema.Block{} - } - - configVal, _, evalDiags := ctx.EvaluateBlock(configBody, configSchema, nil, EvalDataForNoInstanceKey) - if evalDiags.HasErrors() { - return diags.Append(evalDiags) - } - diags = diags.Append(evalDiags) - - // If our config value contains any marked values, ensure those are - // stripped out before sending this to the provider - unmarkedConfigVal, _ := configVal.UnmarkDeep() - - req := providers.ValidateProviderConfigRequest{ - Config: unmarkedConfigVal, - } - - validateResp := provider.ValidateProviderConfig(req) - diags = diags.Append(validateResp.Diagnostics.InConfigBody(configBody, n.Addr.String())) - - return diags -} - -// ConfigureProvider configures a provider that is already initialized and retrieved. -// If verifyConfigIsKnown is true, ConfigureProvider will return an error if the -// provider configVal is not wholly known and is meant only for use during import. -func (n *NodeApplyableProvider) ConfigureProvider(ctx EvalContext, provider providers.Interface, verifyConfigIsKnown bool) (diags tfdiags.Diagnostics) { - config := n.ProviderConfig() - - configBody := buildProviderConfig(ctx, n.Addr, config) - - resp := provider.GetProviderSchema() - diags = diags.Append(resp.Diagnostics.InConfigBody(configBody, n.Addr.String())) - if diags.HasErrors() { - return diags - } - - configSchema := resp.Provider.Block - configVal, configBody, evalDiags := ctx.EvaluateBlock(configBody, configSchema, nil, EvalDataForNoInstanceKey) - diags = diags.Append(evalDiags) - if evalDiags.HasErrors() { - return diags - } - - if verifyConfigIsKnown && !configVal.IsWhollyKnown() { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid provider configuration", - Detail: fmt.Sprintf("The configuration for %s depends on values that cannot be determined until apply.", n.Addr), - Subject: &config.DeclRange, - }) - return diags - } - - // If our config value contains any marked values, ensure those are - // stripped out before sending this to the provider - unmarkedConfigVal, _ := configVal.UnmarkDeep() - - // Allow the provider to validate and insert any defaults into the full - // configuration. - req := providers.ValidateProviderConfigRequest{ - Config: unmarkedConfigVal, - } - - // ValidateProviderConfig is only used for validation. We are intentionally - // ignoring the PreparedConfig field to maintain existing behavior. - validateResp := provider.ValidateProviderConfig(req) - diags = diags.Append(validateResp.Diagnostics.InConfigBody(configBody, n.Addr.String())) - if diags.HasErrors() && config == nil { - // If there isn't an explicit "provider" block in the configuration, - // this error message won't be very clear. Add some detail to the error - // message in this case. - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Invalid provider configuration", - fmt.Sprintf(providerConfigErr, n.Addr.Provider), - )) - } - - if diags.HasErrors() { - return diags - } - - // If the provider returns something different, log a warning to help - // indicate to provider developers that the value is not used. - preparedCfg := validateResp.PreparedConfig - if preparedCfg != cty.NilVal && !preparedCfg.IsNull() && !preparedCfg.RawEquals(unmarkedConfigVal) { - log.Printf("[WARN] ValidateProviderConfig from %q changed the config value, but that value is unused", n.Addr) - } - - configDiags := ctx.ConfigureProvider(n.Addr, unmarkedConfigVal) - diags = diags.Append(configDiags.InConfigBody(configBody, n.Addr.String())) - if diags.HasErrors() && config == nil { - // If there isn't an explicit "provider" block in the configuration, - // this error message won't be very clear. Add some detail to the error - // message in this case. - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Invalid provider configuration", - fmt.Sprintf(providerConfigErr, n.Addr.Provider), - )) - } - return diags -} - -const providerConfigErr = `Provider %q requires explicit configuration. Add a provider block to the root module and configure the provider's required arguments as described in the provider documentation. -` diff --git a/internal/terraform/node_provider_abstract.go b/internal/terraform/node_provider_abstract.go deleted file mode 100644 index 09bdd95b40eb..000000000000 --- a/internal/terraform/node_provider_abstract.go +++ /dev/null @@ -1,95 +0,0 @@ -package terraform - -import ( - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configschema" - - "github.com/hashicorp/terraform/internal/dag" -) - -// ConcreteProviderNodeFunc is a callback type used to convert an -// abstract provider to a concrete one of some type. -type ConcreteProviderNodeFunc func(*NodeAbstractProvider) dag.Vertex - -// NodeAbstractProvider represents a provider that has no associated operations. -// It registers all the common interfaces across operations for providers. -type NodeAbstractProvider struct { - Addr addrs.AbsProviderConfig - - // The fields below will be automatically set using the Attach - // interfaces if you're running those transforms, but also be explicitly - // set if you already have that information. - - Config *configs.Provider - Schema *configschema.Block -} - -var ( - _ GraphNodeModulePath = (*NodeAbstractProvider)(nil) - _ GraphNodeReferencer = (*NodeAbstractProvider)(nil) - _ GraphNodeProvider = (*NodeAbstractProvider)(nil) - _ GraphNodeAttachProvider = (*NodeAbstractProvider)(nil) - _ GraphNodeAttachProviderConfigSchema = (*NodeAbstractProvider)(nil) - _ dag.GraphNodeDotter = (*NodeAbstractProvider)(nil) -) - -func (n *NodeAbstractProvider) Name() string { - return n.Addr.String() -} - -// GraphNodeModuleInstance -func (n *NodeAbstractProvider) Path() addrs.ModuleInstance { - // Providers cannot be contained inside an expanded module, so this shim - // converts our module path to the correct ModuleInstance. - return n.Addr.Module.UnkeyedInstanceShim() -} - -// GraphNodeModulePath -func (n *NodeAbstractProvider) ModulePath() addrs.Module { - return n.Addr.Module -} - -// GraphNodeReferencer -func (n *NodeAbstractProvider) References() []*addrs.Reference { - if n.Config == nil || n.Schema == nil { - return nil - } - - return ReferencesFromConfig(n.Config.Config, n.Schema) -} - -// GraphNodeProvider -func (n *NodeAbstractProvider) ProviderAddr() addrs.AbsProviderConfig { - return n.Addr -} - -// GraphNodeProvider -func (n *NodeAbstractProvider) ProviderConfig() *configs.Provider { - if n.Config == nil { - return nil - } - - return n.Config -} - -// GraphNodeAttachProvider -func (n *NodeAbstractProvider) AttachProvider(c *configs.Provider) { - n.Config = c -} - -// GraphNodeAttachProviderConfigSchema impl. -func (n *NodeAbstractProvider) AttachProviderConfigSchema(schema *configschema.Block) { - n.Schema = schema -} - -// GraphNodeDotter impl. -func (n *NodeAbstractProvider) DotNode(name string, opts *dag.DotOpts) *dag.DotNode { - return &dag.DotNode{ - Name: name, - Attrs: map[string]string{ - "label": n.Name(), - "shape": "diamond", - }, - } -} diff --git a/internal/terraform/node_provider_eval.go b/internal/terraform/node_provider_eval.go deleted file mode 100644 index fba47ddb96f6..000000000000 --- a/internal/terraform/node_provider_eval.go +++ /dev/null @@ -1,19 +0,0 @@ -package terraform - -import "github.com/hashicorp/terraform/internal/tfdiags" - -// NodeEvalableProvider represents a provider during an "eval" walk. -// This special provider node type just initializes a provider and -// fetches its schema, without configuring it or otherwise interacting -// with it. -type NodeEvalableProvider struct { - *NodeAbstractProvider -} - -var _ GraphNodeExecutable = (*NodeEvalableProvider)(nil) - -// GraphNodeExecutable -func (n *NodeEvalableProvider) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) { - _, err := ctx.InitProvider(n.Addr) - return diags.Append(err) -} diff --git a/internal/terraform/node_provider_test.go b/internal/terraform/node_provider_test.go deleted file mode 100644 index fe8a80d11b88..000000000000 --- a/internal/terraform/node_provider_test.go +++ /dev/null @@ -1,524 +0,0 @@ -package terraform - -import ( - "fmt" - "strings" - "testing" - - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/lang/marks" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/tfdiags" - "github.com/zclconf/go-cty/cty" -) - -func TestNodeApplyableProviderExecute(t *testing.T) { - config := &configs.Provider{ - Name: "foo", - Config: configs.SynthBody("", map[string]cty.Value{ - "user": cty.StringVal("hello"), - }), - } - - schema := &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "user": { - Type: cty.String, - Required: true, - }, - "pw": { - Type: cty.String, - Required: true, - }, - }, - } - provider := mockProviderWithConfigSchema(schema) - providerAddr := addrs.AbsProviderConfig{ - Module: addrs.RootModule, - Provider: addrs.NewDefaultProvider("foo"), - } - - n := &NodeApplyableProvider{&NodeAbstractProvider{ - Addr: providerAddr, - Config: config, - }} - - ctx := &MockEvalContext{ProviderProvider: provider} - ctx.installSimpleEval() - ctx.ProviderInputValues = map[string]cty.Value{ - "pw": cty.StringVal("so secret"), - } - - if diags := n.Execute(ctx, walkApply); diags.HasErrors() { - t.Fatalf("err: %s", diags.Err()) - } - - if !ctx.ConfigureProviderCalled { - t.Fatal("should be called") - } - - gotObj := ctx.ConfigureProviderConfig - if !gotObj.Type().HasAttribute("user") { - t.Fatal("configuration object does not have \"user\" attribute") - } - if got, want := gotObj.GetAttr("user"), cty.StringVal("hello"); !got.RawEquals(want) { - t.Errorf("wrong configuration value\ngot: %#v\nwant: %#v", got, want) - } - - if !gotObj.Type().HasAttribute("pw") { - t.Fatal("configuration object does not have \"pw\" attribute") - } - if got, want := gotObj.GetAttr("pw"), cty.StringVal("so secret"); !got.RawEquals(want) { - t.Errorf("wrong configuration value\ngot: %#v\nwant: %#v", got, want) - } -} - -func TestNodeApplyableProviderExecute_unknownImport(t *testing.T) { - config := &configs.Provider{ - Name: "foo", - Config: configs.SynthBody("", map[string]cty.Value{ - "test_string": cty.UnknownVal(cty.String), - }), - } - provider := mockProviderWithConfigSchema(simpleTestSchema()) - providerAddr := addrs.AbsProviderConfig{ - Module: addrs.RootModule, - Provider: addrs.NewDefaultProvider("foo"), - } - n := &NodeApplyableProvider{&NodeAbstractProvider{ - Addr: providerAddr, - Config: config, - }} - - ctx := &MockEvalContext{ProviderProvider: provider} - ctx.installSimpleEval() - - diags := n.Execute(ctx, walkImport) - if !diags.HasErrors() { - t.Fatal("expected error, got success") - } - - detail := `Invalid provider configuration: The configuration for provider["registry.terraform.io/hashicorp/foo"] depends on values that cannot be determined until apply.` - if got, want := diags.Err().Error(), detail; got != want { - t.Errorf("wrong diagnostic detail\n got: %q\nwant: %q", got, want) - } - - if ctx.ConfigureProviderCalled { - t.Fatal("should not be called") - } -} - -func TestNodeApplyableProviderExecute_unknownApply(t *testing.T) { - config := &configs.Provider{ - Name: "foo", - Config: configs.SynthBody("", map[string]cty.Value{ - "test_string": cty.UnknownVal(cty.String), - }), - } - provider := mockProviderWithConfigSchema(simpleTestSchema()) - providerAddr := addrs.AbsProviderConfig{ - Module: addrs.RootModule, - Provider: addrs.NewDefaultProvider("foo"), - } - n := &NodeApplyableProvider{&NodeAbstractProvider{ - Addr: providerAddr, - Config: config, - }} - ctx := &MockEvalContext{ProviderProvider: provider} - ctx.installSimpleEval() - - if err := n.Execute(ctx, walkApply); err != nil { - t.Fatalf("err: %s", err) - } - - if !ctx.ConfigureProviderCalled { - t.Fatal("should be called") - } - - gotObj := ctx.ConfigureProviderConfig - if !gotObj.Type().HasAttribute("test_string") { - t.Fatal("configuration object does not have \"test_string\" attribute") - } - if got, want := gotObj.GetAttr("test_string"), cty.UnknownVal(cty.String); !got.RawEquals(want) { - t.Errorf("wrong configuration value\ngot: %#v\nwant: %#v", got, want) - } -} - -func TestNodeApplyableProviderExecute_sensitive(t *testing.T) { - config := &configs.Provider{ - Name: "foo", - Config: configs.SynthBody("", map[string]cty.Value{ - "test_string": cty.StringVal("hello").Mark(marks.Sensitive), - }), - } - provider := mockProviderWithConfigSchema(simpleTestSchema()) - providerAddr := addrs.AbsProviderConfig{ - Module: addrs.RootModule, - Provider: addrs.NewDefaultProvider("foo"), - } - - n := &NodeApplyableProvider{&NodeAbstractProvider{ - Addr: providerAddr, - Config: config, - }} - - ctx := &MockEvalContext{ProviderProvider: provider} - ctx.installSimpleEval() - if err := n.Execute(ctx, walkApply); err != nil { - t.Fatalf("err: %s", err) - } - - if !ctx.ConfigureProviderCalled { - t.Fatal("should be called") - } - - gotObj := ctx.ConfigureProviderConfig - if !gotObj.Type().HasAttribute("test_string") { - t.Fatal("configuration object does not have \"test_string\" attribute") - } - if got, want := gotObj.GetAttr("test_string"), cty.StringVal("hello"); !got.RawEquals(want) { - t.Errorf("wrong configuration value\ngot: %#v\nwant: %#v", got, want) - } -} - -func TestNodeApplyableProviderExecute_sensitiveValidate(t *testing.T) { - config := &configs.Provider{ - Name: "foo", - Config: configs.SynthBody("", map[string]cty.Value{ - "test_string": cty.StringVal("hello").Mark(marks.Sensitive), - }), - } - provider := mockProviderWithConfigSchema(simpleTestSchema()) - providerAddr := addrs.AbsProviderConfig{ - Module: addrs.RootModule, - Provider: addrs.NewDefaultProvider("foo"), - } - - n := &NodeApplyableProvider{&NodeAbstractProvider{ - Addr: providerAddr, - Config: config, - }} - - ctx := &MockEvalContext{ProviderProvider: provider} - ctx.installSimpleEval() - if err := n.Execute(ctx, walkValidate); err != nil { - t.Fatalf("err: %s", err) - } - - if !provider.ValidateProviderConfigCalled { - t.Fatal("should be called") - } - - gotObj := provider.ValidateProviderConfigRequest.Config - if !gotObj.Type().HasAttribute("test_string") { - t.Fatal("configuration object does not have \"test_string\" attribute") - } - if got, want := gotObj.GetAttr("test_string"), cty.StringVal("hello"); !got.RawEquals(want) { - t.Errorf("wrong configuration value\ngot: %#v\nwant: %#v", got, want) - } -} - -func TestNodeApplyableProviderExecute_emptyValidate(t *testing.T) { - config := &configs.Provider{ - Name: "foo", - Config: configs.SynthBody("", map[string]cty.Value{}), - } - provider := mockProviderWithConfigSchema(&configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "test_string": { - Type: cty.String, - Required: true, - }, - }, - }) - providerAddr := addrs.AbsProviderConfig{ - Module: addrs.RootModule, - Provider: addrs.NewDefaultProvider("foo"), - } - - n := &NodeApplyableProvider{&NodeAbstractProvider{ - Addr: providerAddr, - Config: config, - }} - - ctx := &MockEvalContext{ProviderProvider: provider} - ctx.installSimpleEval() - if err := n.Execute(ctx, walkValidate); err != nil { - t.Fatalf("err: %s", err) - } - - if ctx.ConfigureProviderCalled { - t.Fatal("should not be called") - } -} - -func TestNodeApplyableProvider_Validate(t *testing.T) { - provider := mockProviderWithConfigSchema(&configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "region": { - Type: cty.String, - Required: true, - }, - }, - }) - ctx := &MockEvalContext{ProviderProvider: provider} - ctx.installSimpleEval() - - t.Run("valid", func(t *testing.T) { - config := &configs.Provider{ - Name: "test", - Config: configs.SynthBody("", map[string]cty.Value{ - "region": cty.StringVal("mars"), - }), - } - - node := NodeApplyableProvider{ - NodeAbstractProvider: &NodeAbstractProvider{ - Addr: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - Config: config, - }, - } - - diags := node.ValidateProvider(ctx, provider) - if diags.HasErrors() { - t.Errorf("unexpected error with valid config: %s", diags.Err()) - } - }) - - t.Run("invalid", func(t *testing.T) { - config := &configs.Provider{ - Name: "test", - Config: configs.SynthBody("", map[string]cty.Value{ - "region": cty.MapValEmpty(cty.String), - }), - } - - node := NodeApplyableProvider{ - NodeAbstractProvider: &NodeAbstractProvider{ - Addr: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - Config: config, - }, - } - - diags := node.ValidateProvider(ctx, provider) - if !diags.HasErrors() { - t.Error("missing expected error with invalid config") - } - }) - - t.Run("empty config", func(t *testing.T) { - node := NodeApplyableProvider{ - NodeAbstractProvider: &NodeAbstractProvider{ - Addr: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - }, - } - - diags := node.ValidateProvider(ctx, provider) - if diags.HasErrors() { - t.Errorf("unexpected error with empty config: %s", diags.Err()) - } - }) -} - -// This test specifically tests responses from the -// providers.ValidateProviderConfigFn. See -// TestNodeApplyableProvider_ConfigProvider_config_fn_err for -// providers.ConfigureProviderRequest responses. -func TestNodeApplyableProvider_ConfigProvider(t *testing.T) { - provider := mockProviderWithConfigSchema(&configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "region": { - Type: cty.String, - Optional: true, - }, - }, - }) - // For this test, we're returning an error for an optional argument. This - // can happen for example if an argument is only conditionally required. - provider.ValidateProviderConfigFn = func(req providers.ValidateProviderConfigRequest) (resp providers.ValidateProviderConfigResponse) { - region := req.Config.GetAttr("region") - if region.IsNull() { - resp.Diagnostics = resp.Diagnostics.Append( - tfdiags.WholeContainingBody(tfdiags.Error, "value is not found", "you did not supply a required value")) - } - return - } - ctx := &MockEvalContext{ProviderProvider: provider} - ctx.installSimpleEval() - - t.Run("valid", func(t *testing.T) { - config := &configs.Provider{ - Name: "test", - Config: configs.SynthBody("", map[string]cty.Value{ - "region": cty.StringVal("mars"), - }), - } - - node := NodeApplyableProvider{ - NodeAbstractProvider: &NodeAbstractProvider{ - Addr: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - Config: config, - }, - } - - diags := node.ConfigureProvider(ctx, provider, false) - if diags.HasErrors() { - t.Errorf("unexpected error with valid config: %s", diags.Err()) - } - }) - - t.Run("missing required config (no config at all)", func(t *testing.T) { - node := NodeApplyableProvider{ - NodeAbstractProvider: &NodeAbstractProvider{ - Addr: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - }, - } - - diags := node.ConfigureProvider(ctx, provider, false) - if !diags.HasErrors() { - t.Fatal("missing expected error with nil config") - } - if !strings.Contains(diags.Err().Error(), "requires explicit configuration") { - t.Errorf("diagnostic is missing \"requires explicit configuration\" message: %s", diags.Err()) - } - }) - - t.Run("missing required config", func(t *testing.T) { - config := &configs.Provider{ - Name: "test", - Config: hcl.EmptyBody(), - } - node := NodeApplyableProvider{ - NodeAbstractProvider: &NodeAbstractProvider{ - Addr: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - Config: config, - }, - } - - diags := node.ConfigureProvider(ctx, provider, false) - if !diags.HasErrors() { - t.Fatal("missing expected error with invalid config") - } - if !strings.Contains(diags.Err().Error(), "value is not found") { - t.Errorf("wrong diagnostic: %s", diags.Err()) - } - }) - -} - -// This test is similar to TestNodeApplyableProvider_ConfigProvider, but tests responses from the providers.ConfigureProviderRequest -func TestNodeApplyableProvider_ConfigProvider_config_fn_err(t *testing.T) { - provider := mockProviderWithConfigSchema(&configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "region": { - Type: cty.String, - Optional: true, - }, - }, - }) - ctx := &MockEvalContext{ProviderProvider: provider} - ctx.installSimpleEval() - // For this test, provider.PrepareConfigFn will succeed every time but the - // ctx.ConfigureProviderFn will return an error if a value is not found. - // - // This is an unlikely but real situation that occurs: - // https://github.com/hashicorp/terraform/issues/23087 - ctx.ConfigureProviderFn = func(addr addrs.AbsProviderConfig, cfg cty.Value) (diags tfdiags.Diagnostics) { - if cfg.IsNull() { - diags = diags.Append(fmt.Errorf("no config provided")) - } else { - region := cfg.GetAttr("region") - if region.IsNull() { - diags = diags.Append(fmt.Errorf("value is not found")) - } - } - return - } - - t.Run("valid", func(t *testing.T) { - config := &configs.Provider{ - Name: "test", - Config: configs.SynthBody("", map[string]cty.Value{ - "region": cty.StringVal("mars"), - }), - } - - node := NodeApplyableProvider{ - NodeAbstractProvider: &NodeAbstractProvider{ - Addr: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - Config: config, - }, - } - - diags := node.ConfigureProvider(ctx, provider, false) - if diags.HasErrors() { - t.Errorf("unexpected error with valid config: %s", diags.Err()) - } - }) - - t.Run("missing required config (no config at all)", func(t *testing.T) { - node := NodeApplyableProvider{ - NodeAbstractProvider: &NodeAbstractProvider{ - Addr: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - }, - } - - diags := node.ConfigureProvider(ctx, provider, false) - if !diags.HasErrors() { - t.Fatal("missing expected error with nil config") - } - if !strings.Contains(diags.Err().Error(), "requires explicit configuration") { - t.Errorf("diagnostic is missing \"requires explicit configuration\" message: %s", diags.Err()) - } - }) - - t.Run("missing required config", func(t *testing.T) { - config := &configs.Provider{ - Name: "test", - Config: hcl.EmptyBody(), - } - node := NodeApplyableProvider{ - NodeAbstractProvider: &NodeAbstractProvider{ - Addr: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - Config: config, - }, - } - - diags := node.ConfigureProvider(ctx, provider, false) - if !diags.HasErrors() { - t.Fatal("missing expected error with invalid config") - } - if diags.Err().Error() != "value is not found" { - t.Errorf("wrong diagnostic: %s", diags.Err()) - } - }) -} - -func TestGetSchemaError(t *testing.T) { - provider := &MockProvider{ - GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{ - Diagnostics: tfdiags.Diagnostics.Append(nil, tfdiags.WholeContainingBody(tfdiags.Error, "oops", "error")), - }, - } - - providerAddr := mustProviderConfig(`provider["terraform.io/some/provider"]`) - ctx := &MockEvalContext{ProviderProvider: provider} - ctx.installSimpleEval() - node := NodeApplyableProvider{ - NodeAbstractProvider: &NodeAbstractProvider{ - Addr: providerAddr, - }, - } - - diags := node.ConfigureProvider(ctx, provider, false) - for _, d := range diags { - desc := d.Description() - if desc.Address != providerAddr.String() { - t.Fatalf("missing provider address from diagnostics: %#v", desc) - } - } - -} diff --git a/internal/terraform/node_resource_abstract.go b/internal/terraform/node_resource_abstract.go deleted file mode 100644 index 5ad7901d03fe..000000000000 --- a/internal/terraform/node_resource_abstract.go +++ /dev/null @@ -1,518 +0,0 @@ -package terraform - -import ( - "fmt" - "log" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/dag" - "github.com/hashicorp/terraform/internal/lang" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -// ConcreteResourceNodeFunc is a callback type used to convert an -// abstract resource to a concrete one of some type. -type ConcreteResourceNodeFunc func(*NodeAbstractResource) dag.Vertex - -// GraphNodeConfigResource is implemented by any nodes that represent a resource. -// The type of operation cannot be assumed, only that this node represents -// the given resource. -type GraphNodeConfigResource interface { - ResourceAddr() addrs.ConfigResource -} - -// ConcreteResourceInstanceNodeFunc is a callback type used to convert an -// abstract resource instance to a concrete one of some type. -type ConcreteResourceInstanceNodeFunc func(*NodeAbstractResourceInstance) dag.Vertex - -// GraphNodeResourceInstance is implemented by any nodes that represent -// a resource instance. A single resource may have multiple instances if, -// for example, the "count" or "for_each" argument is used for it in -// configuration. -type GraphNodeResourceInstance interface { - ResourceInstanceAddr() addrs.AbsResourceInstance - - // StateDependencies returns any inter-resource dependencies that are - // stored in the state. - StateDependencies() []addrs.ConfigResource -} - -// NodeAbstractResource represents a resource that has no associated -// operations. It registers all the interfaces for a resource that common -// across multiple operation types. -type NodeAbstractResource struct { - Addr addrs.ConfigResource - - // The fields below will be automatically set using the Attach - // interfaces if you're running those transforms, but also be explicitly - // set if you already have that information. - - Schema *configschema.Block // Schema for processing the configuration body - SchemaVersion uint64 // Schema version of "Schema", as decided by the provider - Config *configs.Resource // Config is the resource in the config - - // ProviderMetas is the provider_meta configs for the module this resource belongs to - ProviderMetas map[addrs.Provider]*configs.ProviderMeta - - ProvisionerSchemas map[string]*configschema.Block - - // Set from GraphNodeTargetable - Targets []addrs.Targetable - - // Set from AttachDataResourceDependsOn - dependsOn []addrs.ConfigResource - forceDependsOn bool - - // The address of the provider this resource will use - ResolvedProvider addrs.AbsProviderConfig - // storedProviderConfig is the provider address retrieved from the - // state. This is defined here for access within the ProvidedBy method, but - // will be set from the embedding instance type when the state is attached. - storedProviderConfig addrs.AbsProviderConfig - - // This resource may expand into instances which need to be imported. - importTargets []*ImportTarget -} - -var ( - _ GraphNodeReferenceable = (*NodeAbstractResource)(nil) - _ GraphNodeReferencer = (*NodeAbstractResource)(nil) - _ GraphNodeProviderConsumer = (*NodeAbstractResource)(nil) - _ GraphNodeProvisionerConsumer = (*NodeAbstractResource)(nil) - _ GraphNodeConfigResource = (*NodeAbstractResource)(nil) - _ GraphNodeAttachResourceConfig = (*NodeAbstractResource)(nil) - _ GraphNodeAttachResourceSchema = (*NodeAbstractResource)(nil) - _ GraphNodeAttachProvisionerSchema = (*NodeAbstractResource)(nil) - _ GraphNodeAttachProviderMetaConfigs = (*NodeAbstractResource)(nil) - _ GraphNodeTargetable = (*NodeAbstractResource)(nil) - _ graphNodeAttachDataResourceDependsOn = (*NodeAbstractResource)(nil) - _ dag.GraphNodeDotter = (*NodeAbstractResource)(nil) -) - -// NewNodeAbstractResource creates an abstract resource graph node for -// the given absolute resource address. -func NewNodeAbstractResource(addr addrs.ConfigResource) *NodeAbstractResource { - return &NodeAbstractResource{ - Addr: addr, - } -} - -var ( - _ GraphNodeModuleInstance = (*NodeAbstractResourceInstance)(nil) - _ GraphNodeReferenceable = (*NodeAbstractResourceInstance)(nil) - _ GraphNodeReferencer = (*NodeAbstractResourceInstance)(nil) - _ GraphNodeProviderConsumer = (*NodeAbstractResourceInstance)(nil) - _ GraphNodeProvisionerConsumer = (*NodeAbstractResourceInstance)(nil) - _ GraphNodeConfigResource = (*NodeAbstractResourceInstance)(nil) - _ GraphNodeResourceInstance = (*NodeAbstractResourceInstance)(nil) - _ GraphNodeAttachResourceState = (*NodeAbstractResourceInstance)(nil) - _ GraphNodeAttachResourceConfig = (*NodeAbstractResourceInstance)(nil) - _ GraphNodeAttachResourceSchema = (*NodeAbstractResourceInstance)(nil) - _ GraphNodeAttachProvisionerSchema = (*NodeAbstractResourceInstance)(nil) - _ GraphNodeAttachProviderMetaConfigs = (*NodeAbstractResourceInstance)(nil) - _ GraphNodeTargetable = (*NodeAbstractResourceInstance)(nil) - _ dag.GraphNodeDotter = (*NodeAbstractResourceInstance)(nil) -) - -func (n *NodeAbstractResource) Name() string { - return n.ResourceAddr().String() -} - -// GraphNodeModulePath -func (n *NodeAbstractResource) ModulePath() addrs.Module { - return n.Addr.Module -} - -// GraphNodeReferenceable -func (n *NodeAbstractResource) ReferenceableAddrs() []addrs.Referenceable { - return []addrs.Referenceable{n.Addr.Resource} -} - -func (n *NodeAbstractResource) Import(addr *ImportTarget) { - -} - -// GraphNodeReferencer -func (n *NodeAbstractResource) References() []*addrs.Reference { - // If we have a config then we prefer to use that. - if c := n.Config; c != nil { - var result []*addrs.Reference - - result = append(result, n.DependsOn()...) - - if n.Schema == nil { - // Should never happen, but we'll log if it does so that we can - // see this easily when debugging. - log.Printf("[WARN] no schema is attached to %s, so config references cannot be detected", n.Name()) - } - - refs, _ := lang.ReferencesInExpr(c.Count) - result = append(result, refs...) - refs, _ = lang.ReferencesInExpr(c.ForEach) - result = append(result, refs...) - - for _, expr := range c.TriggersReplacement { - refs, _ = lang.ReferencesInExpr(expr) - result = append(result, refs...) - } - - // ReferencesInBlock() requires a schema - if n.Schema != nil { - refs, _ = lang.ReferencesInBlock(c.Config, n.Schema) - result = append(result, refs...) - } - - if c.Managed != nil { - if c.Managed.Connection != nil { - refs, _ = lang.ReferencesInBlock(c.Managed.Connection.Config, connectionBlockSupersetSchema) - result = append(result, refs...) - } - - for _, p := range c.Managed.Provisioners { - if p.When != configs.ProvisionerWhenCreate { - continue - } - if p.Connection != nil { - refs, _ = lang.ReferencesInBlock(p.Connection.Config, connectionBlockSupersetSchema) - result = append(result, refs...) - } - - schema := n.ProvisionerSchemas[p.Type] - if schema == nil { - log.Printf("[WARN] no schema for provisioner %q is attached to %s, so provisioner block references cannot be detected", p.Type, n.Name()) - } - refs, _ = lang.ReferencesInBlock(p.Config, schema) - result = append(result, refs...) - } - } - - for _, check := range c.Preconditions { - refs, _ := lang.ReferencesInExpr(check.Condition) - result = append(result, refs...) - refs, _ = lang.ReferencesInExpr(check.ErrorMessage) - result = append(result, refs...) - } - for _, check := range c.Postconditions { - refs, _ := lang.ReferencesInExpr(check.Condition) - result = append(result, refs...) - refs, _ = lang.ReferencesInExpr(check.ErrorMessage) - result = append(result, refs...) - } - - return result - } - - // Otherwise, we have no references. - return nil -} - -func (n *NodeAbstractResource) DependsOn() []*addrs.Reference { - var result []*addrs.Reference - if c := n.Config; c != nil { - - for _, traversal := range c.DependsOn { - ref, diags := addrs.ParseRef(traversal) - if diags.HasErrors() { - // We ignore this here, because this isn't a suitable place to return - // errors. This situation should be caught and rejected during - // validation. - log.Printf("[ERROR] Can't parse %#v from depends_on as reference: %s", traversal, diags.Err()) - continue - } - - result = append(result, ref) - } - } - return result -} - -func (n *NodeAbstractResource) SetProvider(p addrs.AbsProviderConfig) { - n.ResolvedProvider = p -} - -// GraphNodeProviderConsumer -func (n *NodeAbstractResource) ProvidedBy() (addrs.ProviderConfig, bool) { - // Once the provider is fully resolved, we can return the known value. - if n.ResolvedProvider.Provider.Type != "" { - return n.ResolvedProvider, true - } - - // If we have a config we prefer that above all else - if n.Config != nil { - relAddr := n.Config.ProviderConfigAddr() - return addrs.LocalProviderConfig{ - LocalName: relAddr.LocalName, - Alias: relAddr.Alias, - }, false - } - - // See if we have a valid provider config from the state. - if n.storedProviderConfig.Provider.Type != "" { - // An address from the state must match exactly, since we must ensure - // we refresh/destroy a resource with the same provider configuration - // that created it. - return n.storedProviderConfig, true - } - - // No provider configuration found; return a default address - return addrs.AbsProviderConfig{ - Provider: n.Provider(), - Module: n.ModulePath(), - }, false -} - -// GraphNodeProviderConsumer -func (n *NodeAbstractResource) Provider() addrs.Provider { - if n.Config != nil { - return n.Config.Provider - } - if n.storedProviderConfig.Provider.Type != "" { - return n.storedProviderConfig.Provider - } - return addrs.ImpliedProviderForUnqualifiedType(n.Addr.Resource.ImpliedProvider()) -} - -// GraphNodeProvisionerConsumer -func (n *NodeAbstractResource) ProvisionedBy() []string { - // If we have no configuration, then we have no provisioners - if n.Config == nil || n.Config.Managed == nil { - return nil - } - - // Build the list of provisioners we need based on the configuration. - // It is okay to have duplicates here. - result := make([]string, len(n.Config.Managed.Provisioners)) - for i, p := range n.Config.Managed.Provisioners { - result[i] = p.Type - } - - return result -} - -// GraphNodeProvisionerConsumer -func (n *NodeAbstractResource) AttachProvisionerSchema(name string, schema *configschema.Block) { - if n.ProvisionerSchemas == nil { - n.ProvisionerSchemas = make(map[string]*configschema.Block) - } - n.ProvisionerSchemas[name] = schema -} - -// GraphNodeResource -func (n *NodeAbstractResource) ResourceAddr() addrs.ConfigResource { - return n.Addr -} - -// GraphNodeTargetable -func (n *NodeAbstractResource) SetTargets(targets []addrs.Targetable) { - n.Targets = targets -} - -// graphNodeAttachDataResourceDependsOn -func (n *NodeAbstractResource) AttachDataResourceDependsOn(deps []addrs.ConfigResource, force bool) { - n.dependsOn = deps - n.forceDependsOn = force -} - -// GraphNodeAttachResourceConfig -func (n *NodeAbstractResource) AttachResourceConfig(c *configs.Resource) { - n.Config = c -} - -// GraphNodeAttachResourceSchema impl -func (n *NodeAbstractResource) AttachResourceSchema(schema *configschema.Block, version uint64) { - n.Schema = schema - n.SchemaVersion = version -} - -// GraphNodeAttachProviderMetaConfigs impl -func (n *NodeAbstractResource) AttachProviderMetaConfigs(c map[addrs.Provider]*configs.ProviderMeta) { - n.ProviderMetas = c -} - -// GraphNodeDotter impl. -func (n *NodeAbstractResource) DotNode(name string, opts *dag.DotOpts) *dag.DotNode { - return &dag.DotNode{ - Name: name, - Attrs: map[string]string{ - "label": n.Name(), - "shape": "box", - }, - } -} - -// writeResourceState ensures that a suitable resource-level state record is -// present in the state, if that's required for the "each mode" of that -// resource. -// -// This is important primarily for the situation where count = 0, since this -// eval is the only change we get to set the resource "each mode" to list -// in that case, allowing expression evaluation to see it as a zero-element list -// rather than as not set at all. -func (n *NodeAbstractResource) writeResourceState(ctx EvalContext, addr addrs.AbsResource) (diags tfdiags.Diagnostics) { - state := ctx.State() - - // We'll record our expansion decision in the shared "expander" object - // so that later operations (i.e. DynamicExpand and expression evaluation) - // can refer to it. Since this node represents the abstract module, we need - // to expand the module here to create all resources. - expander := ctx.InstanceExpander() - - switch { - case n.Config.Count != nil: - count, countDiags := evaluateCountExpression(n.Config.Count, ctx) - diags = diags.Append(countDiags) - if countDiags.HasErrors() { - return diags - } - - state.SetResourceProvider(addr, n.ResolvedProvider) - expander.SetResourceCount(addr.Module, n.Addr.Resource, count) - - case n.Config.ForEach != nil: - forEach, forEachDiags := evaluateForEachExpression(n.Config.ForEach, ctx) - diags = diags.Append(forEachDiags) - if forEachDiags.HasErrors() { - return diags - } - - // This method takes care of all of the business logic of updating this - // while ensuring that any existing instances are preserved, etc. - state.SetResourceProvider(addr, n.ResolvedProvider) - expander.SetResourceForEach(addr.Module, n.Addr.Resource, forEach) - - default: - state.SetResourceProvider(addr, n.ResolvedProvider) - expander.SetResourceSingle(addr.Module, n.Addr.Resource) - } - - return diags -} - -// readResourceInstanceState reads the current object for a specific instance in -// the state. -func (n *NodeAbstractResource) readResourceInstanceState(ctx EvalContext, addr addrs.AbsResourceInstance) (*states.ResourceInstanceObject, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - provider, providerSchema, err := getProvider(ctx, n.ResolvedProvider) - if err != nil { - diags = diags.Append(err) - return nil, diags - } - - log.Printf("[TRACE] readResourceInstanceState: reading state for %s", addr) - - src := ctx.State().ResourceInstanceObject(addr, states.CurrentGen) - if src == nil { - // Presumably we only have deposed objects, then. - log.Printf("[TRACE] readResourceInstanceState: no state present for %s", addr) - return nil, nil - } - - schema, currentVersion := (providerSchema).SchemaForResourceAddr(addr.Resource.ContainingResource()) - if schema == nil { - // Shouldn't happen since we should've failed long ago if no schema is present - return nil, diags.Append(fmt.Errorf("no schema available for %s while reading state; this is a bug in Terraform and should be reported", addr)) - } - src, upgradeDiags := upgradeResourceState(addr, provider, src, schema, currentVersion) - if n.Config != nil { - upgradeDiags = upgradeDiags.InConfigBody(n.Config.Config, addr.String()) - } - diags = diags.Append(upgradeDiags) - if diags.HasErrors() { - return nil, diags - } - - obj, err := src.Decode(schema.ImpliedType()) - if err != nil { - diags = diags.Append(err) - } - - return obj, diags -} - -// readResourceInstanceStateDeposed reads the deposed object for a specific -// instance in the state. -func (n *NodeAbstractResource) readResourceInstanceStateDeposed(ctx EvalContext, addr addrs.AbsResourceInstance, key states.DeposedKey) (*states.ResourceInstanceObject, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - provider, providerSchema, err := getProvider(ctx, n.ResolvedProvider) - if err != nil { - diags = diags.Append(err) - return nil, diags - } - - if key == states.NotDeposed { - return nil, diags.Append(fmt.Errorf("readResourceInstanceStateDeposed used with no instance key; this is a bug in Terraform and should be reported")) - } - - log.Printf("[TRACE] readResourceInstanceStateDeposed: reading state for %s deposed object %s", addr, key) - - src := ctx.State().ResourceInstanceObject(addr, key) - if src == nil { - // Presumably we only have deposed objects, then. - log.Printf("[TRACE] readResourceInstanceStateDeposed: no state present for %s deposed object %s", addr, key) - return nil, diags - } - - schema, currentVersion := (providerSchema).SchemaForResourceAddr(addr.Resource.ContainingResource()) - if schema == nil { - // Shouldn't happen since we should've failed long ago if no schema is present - return nil, diags.Append(fmt.Errorf("no schema available for %s while reading state; this is a bug in Terraform and should be reported", addr)) - - } - - src, upgradeDiags := upgradeResourceState(addr, provider, src, schema, currentVersion) - if n.Config != nil { - upgradeDiags = upgradeDiags.InConfigBody(n.Config.Config, addr.String()) - } - diags = diags.Append(upgradeDiags) - if diags.HasErrors() { - // Note that we don't have any channel to return warnings here. We'll - // accept that for now since warnings during a schema upgrade would - // be pretty weird anyway, since this operation is supposed to seem - // invisible to the user. - return nil, diags - } - - obj, err := src.Decode(schema.ImpliedType()) - if err != nil { - diags = diags.Append(err) - } - - return obj, diags -} - -// graphNodesAreResourceInstancesInDifferentInstancesOfSameModule is an -// annoyingly-task-specific helper function that returns true if and only if -// the following conditions hold: -// - Both of the given vertices represent specific resource instances, as -// opposed to unexpanded resources or any other non-resource-related object. -// - The module instance addresses for both of the resource instances belong -// to the same static module. -// - The module instance addresses for both of the resource instances are -// not equal, indicating that they belong to different instances of the -// same module. -// -// This result can be used as a way to compensate for the effects of -// conservative analysis passes in our graph builders which make their -// decisions based only on unexpanded addresses, often so that they can behave -// correctly for interactions between expanded and not-yet-expanded objects. -// -// Callers of this helper function will typically skip adding an edge between -// the two given nodes if this function returns true. -func graphNodesAreResourceInstancesInDifferentInstancesOfSameModule(a, b dag.Vertex) bool { - aRI, aOK := a.(GraphNodeResourceInstance) - bRI, bOK := b.(GraphNodeResourceInstance) - if !(aOK && bOK) { - return false - } - aModInst := aRI.ResourceInstanceAddr().Module - bModInst := bRI.ResourceInstanceAddr().Module - aMod := aModInst.Module() - bMod := bModInst.Module() - if !aMod.Equal(bMod) { - return false - } - return !aModInst.Equal(bModInst) -} diff --git a/internal/terraform/node_resource_abstract_instance.go b/internal/terraform/node_resource_abstract_instance.go deleted file mode 100644 index d14d0d92ff76..000000000000 --- a/internal/terraform/node_resource_abstract_instance.go +++ /dev/null @@ -1,2400 +0,0 @@ -package terraform - -import ( - "fmt" - "log" - "strings" - - "github.com/hashicorp/hcl/v2" - "github.com/zclconf/go-cty/cty" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/instances" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/plans/objchange" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/provisioners" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -// NodeAbstractResourceInstance represents a resource instance with no -// associated operations. It embeds NodeAbstractResource but additionally -// contains an instance key, used to identify one of potentially many -// instances that were created from a resource in configuration, e.g. using -// the "count" or "for_each" arguments. -type NodeAbstractResourceInstance struct { - NodeAbstractResource - Addr addrs.AbsResourceInstance - - // These are set via the AttachState method. - instanceState *states.ResourceInstance - - Dependencies []addrs.ConfigResource - - preDestroyRefresh bool -} - -// NewNodeAbstractResourceInstance creates an abstract resource instance graph -// node for the given absolute resource instance address. -func NewNodeAbstractResourceInstance(addr addrs.AbsResourceInstance) *NodeAbstractResourceInstance { - // Due to the fact that we embed NodeAbstractResource, the given address - // actually ends up split between the resource address in the embedded - // object and the InstanceKey field in our own struct. The - // ResourceInstanceAddr method will stick these back together again on - // request. - r := NewNodeAbstractResource(addr.ContainingResource().Config()) - return &NodeAbstractResourceInstance{ - NodeAbstractResource: *r, - Addr: addr, - } -} - -func (n *NodeAbstractResourceInstance) Name() string { - return n.ResourceInstanceAddr().String() -} - -func (n *NodeAbstractResourceInstance) Path() addrs.ModuleInstance { - return n.Addr.Module -} - -// GraphNodeReferenceable -func (n *NodeAbstractResourceInstance) ReferenceableAddrs() []addrs.Referenceable { - addr := n.ResourceInstanceAddr() - return []addrs.Referenceable{ - addr.Resource, - - // A resource instance can also be referenced by the address of its - // containing resource, so that e.g. a reference to aws_instance.foo - // would match both aws_instance.foo[0] and aws_instance.foo[1]. - addr.ContainingResource().Resource, - } -} - -// GraphNodeReferencer -func (n *NodeAbstractResourceInstance) References() []*addrs.Reference { - // If we have a configuration attached then we'll delegate to our - // embedded abstract resource, which knows how to extract dependencies - // from configuration. If there is no config, then the dependencies will - // be connected during destroy from those stored in the state. - if n.Config != nil { - if n.Schema == nil { - // We'll produce a log message about this out here so that - // we can include the full instance address, since the equivalent - // message in NodeAbstractResource.References cannot see it. - log.Printf("[WARN] no schema is attached to %s, so config references cannot be detected", n.Name()) - return nil - } - return n.NodeAbstractResource.References() - } - - // If we have neither config nor state then we have no references. - return nil -} - -// StateDependencies returns the dependencies which will be saved in the state -// for managed resources, or the most current dependencies for data resources. -func (n *NodeAbstractResourceInstance) StateDependencies() []addrs.ConfigResource { - // Managed resources prefer the stored dependencies, to avoid possible - // conflicts in ordering when refactoring configuration. - if s := n.instanceState; s != nil { - if s.Current != nil { - return s.Current.Dependencies - } - } - - // If there are no stored dependencies, this is either a newly created - // managed resource, or a data source, and we can use the most recently - // calculated dependencies. - return n.Dependencies -} - -// GraphNodeResourceInstance -func (n *NodeAbstractResourceInstance) ResourceInstanceAddr() addrs.AbsResourceInstance { - return n.Addr -} - -// GraphNodeAttachResourceState -func (n *NodeAbstractResourceInstance) AttachResourceState(s *states.Resource) { - if s == nil { - log.Printf("[WARN] attaching nil state to %s", n.Addr) - return - } - log.Printf("[TRACE] NodeAbstractResourceInstance.AttachResourceState for %s", n.Addr) - n.instanceState = s.Instance(n.Addr.Resource.Key) - n.storedProviderConfig = s.ProviderConfig -} - -// readDiff returns the planned change for a particular resource instance -// object. -func (n *NodeAbstractResourceInstance) readDiff(ctx EvalContext, providerSchema *ProviderSchema) (*plans.ResourceInstanceChange, error) { - changes := ctx.Changes() - addr := n.ResourceInstanceAddr() - - schema, _ := providerSchema.SchemaForResourceAddr(addr.Resource.Resource) - if schema == nil { - // Should be caught during validation, so we don't bother with a pretty error here - return nil, fmt.Errorf("provider does not support resource type %q", addr.Resource.Resource.Type) - } - - gen := states.CurrentGen - csrc := changes.GetResourceInstanceChange(addr, gen) - if csrc == nil { - log.Printf("[TRACE] readDiff: No planned change recorded for %s", n.Addr) - return nil, nil - } - - change, err := csrc.Decode(schema.ImpliedType()) - if err != nil { - return nil, fmt.Errorf("failed to decode planned changes for %s: %s", n.Addr, err) - } - - log.Printf("[TRACE] readDiff: Read %s change from plan for %s", change.Action, n.Addr) - - return change, nil -} - -func (n *NodeAbstractResourceInstance) checkPreventDestroy(change *plans.ResourceInstanceChange) error { - if change == nil || n.Config == nil || n.Config.Managed == nil { - return nil - } - - preventDestroy := n.Config.Managed.PreventDestroy - - if (change.Action == plans.Delete || change.Action.IsReplace()) && preventDestroy { - var diags tfdiags.Diagnostics - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Instance cannot be destroyed", - Detail: fmt.Sprintf( - "Resource %s has lifecycle.prevent_destroy set, but the plan calls for this resource to be destroyed. To avoid this error and continue with the plan, either disable lifecycle.prevent_destroy or reduce the scope of the plan using the -target flag.", - n.Addr.String(), - ), - Subject: &n.Config.DeclRange, - }) - return diags.Err() - } - - return nil -} - -// preApplyHook calls the pre-Apply hook -func (n *NodeAbstractResourceInstance) preApplyHook(ctx EvalContext, change *plans.ResourceInstanceChange) tfdiags.Diagnostics { - var diags tfdiags.Diagnostics - - if change == nil { - panic(fmt.Sprintf("preApplyHook for %s called with nil Change", n.Addr)) - } - - // Only managed resources have user-visible apply actions. - if n.Addr.Resource.Resource.Mode == addrs.ManagedResourceMode { - priorState := change.Before - plannedNewState := change.After - - diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) { - return h.PreApply(n.Addr, change.DeposedKey.Generation(), change.Action, priorState, plannedNewState) - })) - if diags.HasErrors() { - return diags - } - } - - return nil -} - -// postApplyHook calls the post-Apply hook -func (n *NodeAbstractResourceInstance) postApplyHook(ctx EvalContext, state *states.ResourceInstanceObject, err error) tfdiags.Diagnostics { - var diags tfdiags.Diagnostics - - // Only managed resources have user-visible apply actions. - if n.Addr.Resource.Resource.Mode == addrs.ManagedResourceMode { - var newState cty.Value - if state != nil { - newState = state.Value - } else { - newState = cty.NullVal(cty.DynamicPseudoType) - } - diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) { - return h.PostApply(n.Addr, nil, newState, err) - })) - } - - return diags -} - -type phaseState int - -const ( - workingState phaseState = iota - refreshState - prevRunState -) - -//go:generate go run golang.org/x/tools/cmd/stringer -type phaseState - -// writeResourceInstanceState saves the given object as the current object for -// the selected resource instance. -// -// dependencies is a parameter, instead of those directly attacted to the -// NodeAbstractResourceInstance, because we don't write dependencies for -// datasources. -// -// targetState determines which context state we're writing to during plan. The -// default is the global working state. -func (n *NodeAbstractResourceInstance) writeResourceInstanceState(ctx EvalContext, obj *states.ResourceInstanceObject, targetState phaseState) error { - return n.writeResourceInstanceStateImpl(ctx, states.NotDeposed, obj, targetState) -} - -func (n *NodeAbstractResourceInstance) writeResourceInstanceStateDeposed(ctx EvalContext, deposedKey states.DeposedKey, obj *states.ResourceInstanceObject, targetState phaseState) error { - if deposedKey == states.NotDeposed { - // Bail out to avoid silently doing something other than what the - // caller seems to have intended. - panic("trying to write current state object using writeResourceInstanceStateDeposed") - } - return n.writeResourceInstanceStateImpl(ctx, deposedKey, obj, targetState) -} - -// (this is the private common body of both writeResourceInstanceState and -// writeResourceInstanceStateDeposed. Don't call it directly; instead, use -// one of the two wrappers to be explicit about which of the instance's -// objects you are intending to write. -func (n *NodeAbstractResourceInstance) writeResourceInstanceStateImpl(ctx EvalContext, deposedKey states.DeposedKey, obj *states.ResourceInstanceObject, targetState phaseState) error { - absAddr := n.Addr - _, providerSchema, err := getProvider(ctx, n.ResolvedProvider) - if err != nil { - return err - } - logFuncName := "NodeAbstractResouceInstance.writeResourceInstanceState" - if deposedKey == states.NotDeposed { - log.Printf("[TRACE] %s to %s for %s", logFuncName, targetState, absAddr) - } else { - logFuncName = "NodeAbstractResouceInstance.writeResourceInstanceStateDeposed" - log.Printf("[TRACE] %s to %s for %s (deposed key %s)", logFuncName, targetState, absAddr, deposedKey) - } - - var state *states.SyncState - switch targetState { - case workingState: - state = ctx.State() - case refreshState: - state = ctx.RefreshState() - case prevRunState: - state = ctx.PrevRunState() - default: - panic(fmt.Sprintf("unsupported phaseState value %#v", targetState)) - } - if state == nil { - // Should not happen, because we shouldn't ever try to write to - // a state that isn't applicable to the current operation. - // (We can also get in here for unit tests which are using - // EvalContextMock but not populating PrevRunStateState with - // a suitable state object.) - return fmt.Errorf("state of type %s is not applicable to the current operation; this is a bug in Terraform", targetState) - } - - // In spite of the name, this function also handles the non-deposed case - // via the writeResourceInstanceState wrapper, by setting deposedKey to - // the NotDeposed value (the zero value of DeposedKey). - var write func(src *states.ResourceInstanceObjectSrc) - if deposedKey == states.NotDeposed { - write = func(src *states.ResourceInstanceObjectSrc) { - state.SetResourceInstanceCurrent(absAddr, src, n.ResolvedProvider) - } - } else { - write = func(src *states.ResourceInstanceObjectSrc) { - state.SetResourceInstanceDeposed(absAddr, deposedKey, src, n.ResolvedProvider) - } - } - - if obj == nil || obj.Value.IsNull() { - // No need to encode anything: we'll just write it directly. - write(nil) - log.Printf("[TRACE] %s: removing state object for %s", logFuncName, absAddr) - return nil - } - - if providerSchema == nil { - // Should never happen, unless our state object is nil - panic("writeResourceInstanceStateImpl used with nil ProviderSchema") - } - - if obj != nil { - log.Printf("[TRACE] %s: writing state object for %s", logFuncName, absAddr) - } else { - log.Printf("[TRACE] %s: removing state object for %s", logFuncName, absAddr) - } - - schema, currentVersion := (*providerSchema).SchemaForResourceAddr(absAddr.ContainingResource().Resource) - if schema == nil { - // It shouldn't be possible to get this far in any real scenario - // without a schema, but we might end up here in contrived tests that - // fail to set up their world properly. - return fmt.Errorf("failed to encode %s in state: no resource type schema available", absAddr) - } - - src, err := obj.Encode(schema.ImpliedType(), currentVersion) - if err != nil { - return fmt.Errorf("failed to encode %s in state: %s", absAddr, err) - } - - write(src) - return nil -} - -// planDestroy returns a plain destroy diff. -func (n *NodeAbstractResourceInstance) planDestroy(ctx EvalContext, currentState *states.ResourceInstanceObject, deposedKey states.DeposedKey) (*plans.ResourceInstanceChange, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - var plan *plans.ResourceInstanceChange - - absAddr := n.Addr - - if n.ResolvedProvider.Provider.Type == "" { - if deposedKey == "" { - panic(fmt.Sprintf("planDestroy for %s does not have ProviderAddr set", absAddr)) - } else { - panic(fmt.Sprintf("planDestroy for %s (deposed %s) does not have ProviderAddr set", absAddr, deposedKey)) - } - } - - // If there is no state or our attributes object is null then we're already - // destroyed. - if currentState == nil || currentState.Value.IsNull() { - // We still need to generate a NoOp change, because that allows - // outside consumers of the plan to distinguish between us affirming - // that we checked something and concluded no changes were needed - // vs. that something being entirely excluded e.g. due to -target. - noop := &plans.ResourceInstanceChange{ - Addr: absAddr, - PrevRunAddr: n.prevRunAddr(ctx), - DeposedKey: deposedKey, - Change: plans.Change{ - Action: plans.NoOp, - Before: cty.NullVal(cty.DynamicPseudoType), - After: cty.NullVal(cty.DynamicPseudoType), - }, - ProviderAddr: n.ResolvedProvider, - } - return noop, nil - } - - unmarkedPriorVal, _ := currentState.Value.UnmarkDeep() - - // The config and new value are null to signify that this is a destroy - // operation. - nullVal := cty.NullVal(unmarkedPriorVal.Type()) - - provider, _, err := getProvider(ctx, n.ResolvedProvider) - if err != nil { - return plan, diags.Append(err) - } - - metaConfigVal, metaDiags := n.providerMetas(ctx) - diags = diags.Append(metaDiags) - if diags.HasErrors() { - return plan, diags - } - - // Allow the provider to check the destroy plan, and insert any necessary - // private data. - resp := provider.PlanResourceChange(providers.PlanResourceChangeRequest{ - TypeName: n.Addr.Resource.Resource.Type, - Config: nullVal, - PriorState: unmarkedPriorVal, - ProposedNewState: nullVal, - PriorPrivate: currentState.Private, - ProviderMeta: metaConfigVal, - }) - - // We may not have a config for all destroys, but we want to reference it in - // the diagnostics if we do. - if n.Config != nil { - resp.Diagnostics = resp.Diagnostics.InConfigBody(n.Config.Config, n.Addr.String()) - } - diags = diags.Append(resp.Diagnostics) - if diags.HasErrors() { - return plan, diags - } - - // Check that the provider returned a null value here, since that is the - // only valid value for a destroy plan. - if !resp.PlannedState.IsNull() { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Provider produced invalid plan", - fmt.Sprintf( - "Provider %q planned a non-null destroy value for %s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.", - n.ResolvedProvider.Provider, n.Addr), - ), - ) - return plan, diags - } - - // Plan is always the same for a destroy. - plan = &plans.ResourceInstanceChange{ - Addr: absAddr, - PrevRunAddr: n.prevRunAddr(ctx), - DeposedKey: deposedKey, - Change: plans.Change{ - Action: plans.Delete, - Before: currentState.Value, - After: nullVal, - }, - Private: resp.PlannedPrivate, - ProviderAddr: n.ResolvedProvider, - } - - return plan, diags -} - -// writeChange saves a planned change for an instance object into the set of -// global planned changes. -func (n *NodeAbstractResourceInstance) writeChange(ctx EvalContext, change *plans.ResourceInstanceChange, deposedKey states.DeposedKey) error { - changes := ctx.Changes() - - if change == nil { - // Caller sets nil to indicate that we need to remove a change from - // the set of changes. - gen := states.CurrentGen - if deposedKey != states.NotDeposed { - gen = deposedKey - } - changes.RemoveResourceInstanceChange(n.Addr, gen) - return nil - } - - _, providerSchema, err := getProvider(ctx, n.ResolvedProvider) - if err != nil { - return err - } - - if change.Addr.String() != n.Addr.String() || change.DeposedKey != deposedKey { - // Should never happen, and indicates a bug in the caller. - panic("inconsistent address and/or deposed key in writeChange") - } - if change.PrevRunAddr.Resource.Resource.Type == "" { - // Should never happen, and indicates a bug in the caller. - // (The change.Encode function actually has its own fixup to just - // quietly make this match change.Addr in the incorrect case, but we - // intentionally panic here in order to catch incorrect callers where - // the stack trace will hopefully be actually useful. The tolerance - // at the next layer down is mainly to accommodate sloppy input in - // older tests.) - panic("unpopulated ResourceInstanceChange.PrevRunAddr in writeChange") - } - - ri := n.Addr.Resource - schema, _ := providerSchema.SchemaForResourceAddr(ri.Resource) - if schema == nil { - // Should be caught during validation, so we don't bother with a pretty error here - return fmt.Errorf("provider does not support resource type %q", ri.Resource.Type) - } - - csrc, err := change.Encode(schema.ImpliedType()) - if err != nil { - return fmt.Errorf("failed to encode planned changes for %s: %s", n.Addr, err) - } - - changes.AppendResourceInstanceChange(csrc) - if deposedKey == states.NotDeposed { - log.Printf("[TRACE] writeChange: recorded %s change for %s", change.Action, n.Addr) - } else { - log.Printf("[TRACE] writeChange: recorded %s change for %s deposed object %s", change.Action, n.Addr, deposedKey) - } - - return nil -} - -// refresh does a refresh for a resource -func (n *NodeAbstractResourceInstance) refresh(ctx EvalContext, deposedKey states.DeposedKey, state *states.ResourceInstanceObject) (*states.ResourceInstanceObject, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - absAddr := n.Addr - if deposedKey == states.NotDeposed { - log.Printf("[TRACE] NodeAbstractResourceInstance.refresh for %s", absAddr) - } else { - log.Printf("[TRACE] NodeAbstractResourceInstance.refresh for %s (deposed object %s)", absAddr, deposedKey) - } - provider, providerSchema, err := getProvider(ctx, n.ResolvedProvider) - if err != nil { - return state, diags.Append(err) - } - // If we have no state, we don't do any refreshing - if state == nil { - log.Printf("[DEBUG] refresh: %s: no state, so not refreshing", absAddr) - return state, diags - } - - schema, _ := providerSchema.SchemaForResourceAddr(n.Addr.Resource.ContainingResource()) - if schema == nil { - // Should be caught during validation, so we don't bother with a pretty error here - diags = diags.Append(fmt.Errorf("provider does not support resource type %q", n.Addr.Resource.Resource.Type)) - return state, diags - } - - metaConfigVal, metaDiags := n.providerMetas(ctx) - diags = diags.Append(metaDiags) - if diags.HasErrors() { - return state, diags - } - - hookGen := states.CurrentGen - if deposedKey != states.NotDeposed { - hookGen = deposedKey - } - - // Call pre-refresh hook - diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) { - return h.PreRefresh(absAddr, hookGen, state.Value) - })) - if diags.HasErrors() { - return state, diags - } - - // Refresh! - priorVal := state.Value - - // Unmarked before sending to provider - var priorPaths []cty.PathValueMarks - if priorVal.ContainsMarked() { - priorVal, priorPaths = priorVal.UnmarkDeepWithPaths() - } - - providerReq := providers.ReadResourceRequest{ - TypeName: n.Addr.Resource.Resource.Type, - PriorState: priorVal, - Private: state.Private, - ProviderMeta: metaConfigVal, - } - - resp := provider.ReadResource(providerReq) - if n.Config != nil { - resp.Diagnostics = resp.Diagnostics.InConfigBody(n.Config.Config, n.Addr.String()) - } - - diags = diags.Append(resp.Diagnostics) - if diags.HasErrors() { - return state, diags - } - - if resp.NewState == cty.NilVal { - // This ought not to happen in real cases since it's not possible to - // send NilVal over the plugin RPC channel, but it can come up in - // tests due to sloppy mocking. - panic("new state is cty.NilVal") - } - - for _, err := range resp.NewState.Type().TestConformance(schema.ImpliedType()) { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Provider produced invalid object", - fmt.Sprintf( - "Provider %q planned an invalid value for %s during refresh: %s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.", - n.ResolvedProvider.Provider.String(), absAddr, tfdiags.FormatError(err), - ), - )) - } - if diags.HasErrors() { - return state, diags - } - - newState := objchange.NormalizeObjectFromLegacySDK(resp.NewState, schema) - if !newState.RawEquals(resp.NewState) { - // We had to fix up this object in some way, and we still need to - // accept any changes for compatibility, so all we can do is log a - // warning about the change. - log.Printf("[WARN] Provider %q produced an invalid new value containing null blocks for %q during refresh\n", n.ResolvedProvider.Provider, n.Addr) - } - - ret := state.DeepCopy() - ret.Value = newState - ret.Private = resp.Private - - // We have no way to exempt provider using the legacy SDK from this check, - // so we can only log inconsistencies with the updated state values. - // In most cases these are not errors anyway, and represent "drift" from - // external changes which will be handled by the subsequent plan. - if errs := objchange.AssertObjectCompatible(schema, priorVal, ret.Value); len(errs) > 0 { - var buf strings.Builder - fmt.Fprintf(&buf, "[WARN] Provider %q produced an unexpected new value for %s during refresh.", n.ResolvedProvider.Provider.String(), absAddr) - for _, err := range errs { - fmt.Fprintf(&buf, "\n - %s", tfdiags.FormatError(err)) - } - log.Print(buf.String()) - } - - // Call post-refresh hook - diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) { - return h.PostRefresh(absAddr, hookGen, priorVal, ret.Value) - })) - if diags.HasErrors() { - return ret, diags - } - - // Mark the value if necessary - if len(priorPaths) > 0 { - ret.Value = ret.Value.MarkWithPaths(priorPaths) - } - - return ret, diags -} - -func (n *NodeAbstractResourceInstance) plan( - ctx EvalContext, - plannedChange *plans.ResourceInstanceChange, - currentState *states.ResourceInstanceObject, - createBeforeDestroy bool, - forceReplace []addrs.AbsResourceInstance) (*plans.ResourceInstanceChange, *states.ResourceInstanceObject, instances.RepetitionData, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - var state *states.ResourceInstanceObject - var plan *plans.ResourceInstanceChange - var keyData instances.RepetitionData - - config := *n.Config - resource := n.Addr.Resource.Resource - provider, providerSchema, err := getProvider(ctx, n.ResolvedProvider) - if err != nil { - return plan, state, keyData, diags.Append(err) - } - - checkRuleSeverity := tfdiags.Error - if n.preDestroyRefresh { - checkRuleSeverity = tfdiags.Warning - } - - if plannedChange != nil { - // If we already planned the action, we stick to that plan - createBeforeDestroy = plannedChange.Action == plans.CreateThenDelete - } - - if providerSchema == nil { - diags = diags.Append(fmt.Errorf("provider schema is unavailable for %s", n.Addr)) - return plan, state, keyData, diags - } - - // Evaluate the configuration - schema, _ := providerSchema.SchemaForResourceAddr(resource) - if schema == nil { - // Should be caught during validation, so we don't bother with a pretty error here - diags = diags.Append(fmt.Errorf("provider does not support resource type %q", resource.Type)) - return plan, state, keyData, diags - } - - forEach, _ := evaluateForEachExpression(n.Config.ForEach, ctx) - - keyData = EvalDataForInstanceKey(n.ResourceInstanceAddr().Resource.Key, forEach) - - checkDiags := evalCheckRules( - addrs.ResourcePrecondition, - n.Config.Preconditions, - ctx, n.Addr, keyData, - checkRuleSeverity, - ) - diags = diags.Append(checkDiags) - if diags.HasErrors() { - return plan, state, keyData, diags // failed preconditions prevent further evaluation - } - - // If we have a previous plan and the action was a noop, then the only - // reason we're in this method was to evaluate the preconditions. There's - // no need to re-plan this resource. - if plannedChange != nil && plannedChange.Action == plans.NoOp { - return plannedChange, currentState.DeepCopy(), keyData, diags - } - - origConfigVal, _, configDiags := ctx.EvaluateBlock(config.Config, schema, nil, keyData) - diags = diags.Append(configDiags) - if configDiags.HasErrors() { - return plan, state, keyData, diags - } - - metaConfigVal, metaDiags := n.providerMetas(ctx) - diags = diags.Append(metaDiags) - if diags.HasErrors() { - return plan, state, keyData, diags - } - - var priorVal cty.Value - var priorValTainted cty.Value - var priorPrivate []byte - if currentState != nil { - if currentState.Status != states.ObjectTainted { - priorVal = currentState.Value - priorPrivate = currentState.Private - } else { - // If the prior state is tainted then we'll proceed below like - // we're creating an entirely new object, but then turn it into - // a synthetic "Replace" change at the end, creating the same - // result as if the provider had marked at least one argument - // change as "requires replacement". - priorValTainted = currentState.Value - priorVal = cty.NullVal(schema.ImpliedType()) - } - } else { - priorVal = cty.NullVal(schema.ImpliedType()) - } - - log.Printf("[TRACE] Re-validating config for %q", n.Addr) - // Allow the provider to validate the final set of values. The config was - // statically validated early on, but there may have been unknown values - // which the provider could not validate at the time. - // - // TODO: It would be more correct to validate the config after - // ignore_changes has been applied, but the current implementation cannot - // exclude computed-only attributes when given the `all` option. - - // we must unmark and use the original config, since the ignore_changes - // handling below needs access to the marks. - unmarkedConfigVal, _ := origConfigVal.UnmarkDeep() - validateResp := provider.ValidateResourceConfig( - providers.ValidateResourceConfigRequest{ - TypeName: n.Addr.Resource.Resource.Type, - Config: unmarkedConfigVal, - }, - ) - diags = diags.Append(validateResp.Diagnostics.InConfigBody(config.Config, n.Addr.String())) - if diags.HasErrors() { - return plan, state, keyData, diags - } - - // ignore_changes is meant to only apply to the configuration, so it must - // be applied before we generate a plan. This ensures the config used for - // the proposed value, the proposed value itself, and the config presented - // to the provider in the PlanResourceChange request all agree on the - // starting values. - // Here we operate on the marked values, so as to revert any changes to the - // marks as well as the value. - configValIgnored, ignoreChangeDiags := n.processIgnoreChanges(priorVal, origConfigVal, schema) - diags = diags.Append(ignoreChangeDiags) - if ignoreChangeDiags.HasErrors() { - return plan, state, keyData, diags - } - - // Create an unmarked version of our config val and our prior val. - // Store the paths for the config val to re-mark after we've sent things - // over the wire. - unmarkedConfigVal, unmarkedPaths := configValIgnored.UnmarkDeepWithPaths() - unmarkedPriorVal, priorPaths := priorVal.UnmarkDeepWithPaths() - - proposedNewVal := objchange.ProposedNew(schema, unmarkedPriorVal, unmarkedConfigVal) - - // Call pre-diff hook - diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) { - return h.PreDiff(n.Addr, states.CurrentGen, priorVal, proposedNewVal) - })) - if diags.HasErrors() { - return plan, state, keyData, diags - } - - resp := provider.PlanResourceChange(providers.PlanResourceChangeRequest{ - TypeName: n.Addr.Resource.Resource.Type, - Config: unmarkedConfigVal, - PriorState: unmarkedPriorVal, - ProposedNewState: proposedNewVal, - PriorPrivate: priorPrivate, - ProviderMeta: metaConfigVal, - }) - diags = diags.Append(resp.Diagnostics.InConfigBody(config.Config, n.Addr.String())) - if diags.HasErrors() { - return plan, state, keyData, diags - } - - plannedNewVal := resp.PlannedState - plannedPrivate := resp.PlannedPrivate - - if plannedNewVal == cty.NilVal { - // Should never happen. Since real-world providers return via RPC a nil - // is always a bug in the client-side stub. This is more likely caused - // by an incompletely-configured mock provider in tests, though. - panic(fmt.Sprintf("PlanResourceChange of %s produced nil value", n.Addr)) - } - - // We allow the planned new value to disagree with configuration _values_ - // here, since that allows the provider to do special logic like a - // DiffSuppressFunc, but we still require that the provider produces - // a value whose type conforms to the schema. - for _, err := range plannedNewVal.Type().TestConformance(schema.ImpliedType()) { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Provider produced invalid plan", - fmt.Sprintf( - "Provider %q planned an invalid value for %s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.", - n.ResolvedProvider.Provider, tfdiags.FormatErrorPrefixed(err, n.Addr.String()), - ), - )) - } - if diags.HasErrors() { - return plan, state, keyData, diags - } - - if errs := objchange.AssertPlanValid(schema, unmarkedPriorVal, unmarkedConfigVal, plannedNewVal); len(errs) > 0 { - if resp.LegacyTypeSystem { - // The shimming of the old type system in the legacy SDK is not precise - // enough to pass this consistency check, so we'll give it a pass here, - // but we will generate a warning about it so that we are more likely - // to notice in the logs if an inconsistency beyond the type system - // leads to a downstream provider failure. - var buf strings.Builder - fmt.Fprintf(&buf, - "[WARN] Provider %q produced an invalid plan for %s, but we are tolerating it because it is using the legacy plugin SDK.\n The following problems may be the cause of any confusing errors from downstream operations:", - n.ResolvedProvider.Provider, n.Addr, - ) - for _, err := range errs { - fmt.Fprintf(&buf, "\n - %s", tfdiags.FormatError(err)) - } - log.Print(buf.String()) - } else { - for _, err := range errs { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Provider produced invalid plan", - fmt.Sprintf( - "Provider %q planned an invalid value for %s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.", - n.ResolvedProvider.Provider, tfdiags.FormatErrorPrefixed(err, n.Addr.String()), - ), - )) - } - return plan, state, keyData, diags - } - } - - if resp.LegacyTypeSystem { - // Because we allow legacy providers to depart from the contract and - // return changes to non-computed values, the plan response may have - // altered values that were already suppressed with ignore_changes. - // A prime example of this is where providers attempt to obfuscate - // config data by turning the config value into a hash and storing the - // hash value in the state. There are enough cases of this in existing - // providers that we must accommodate the behavior for now, so for - // ignore_changes to work at all on these values, we will revert the - // ignored values once more. - // A nil schema is passed to processIgnoreChanges to indicate that we - // don't want to fixup a config value according to the schema when - // ignoring "all", rather we are reverting provider imposed changes. - plannedNewVal, ignoreChangeDiags = n.processIgnoreChanges(unmarkedPriorVal, plannedNewVal, nil) - diags = diags.Append(ignoreChangeDiags) - if ignoreChangeDiags.HasErrors() { - return plan, state, keyData, diags - } - } - - // Add the marks back to the planned new value -- this must happen after ignore changes - // have been processed - unmarkedPlannedNewVal := plannedNewVal - if len(unmarkedPaths) > 0 { - plannedNewVal = plannedNewVal.MarkWithPaths(unmarkedPaths) - } - - // The provider produces a list of paths to attributes whose changes mean - // that we must replace rather than update an existing remote object. - // However, we only need to do that if the identified attributes _have_ - // actually changed -- particularly after we may have undone some of the - // changes in processIgnoreChanges -- so now we'll filter that list to - // include only where changes are detected. - reqRep := cty.NewPathSet() - if len(resp.RequiresReplace) > 0 { - for _, path := range resp.RequiresReplace { - if priorVal.IsNull() { - // If prior is null then we don't expect any RequiresReplace at all, - // because this is a Create action. - continue - } - - priorChangedVal, priorPathDiags := hcl.ApplyPath(unmarkedPriorVal, path, nil) - plannedChangedVal, plannedPathDiags := hcl.ApplyPath(plannedNewVal, path, nil) - if plannedPathDiags.HasErrors() && priorPathDiags.HasErrors() { - // This means the path was invalid in both the prior and new - // values, which is an error with the provider itself. - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Provider produced invalid plan", - fmt.Sprintf( - "Provider %q has indicated \"requires replacement\" on %s for a non-existent attribute path %#v.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.", - n.ResolvedProvider.Provider, n.Addr, path, - ), - )) - continue - } - - // Make sure we have valid Values for both values. - // Note: if the opposing value was of the type - // cty.DynamicPseudoType, the type assigned here may not exactly - // match the schema. This is fine here, since we're only going to - // check for equality, but if the NullVal is to be used, we need to - // check the schema for th true type. - switch { - case priorChangedVal == cty.NilVal && plannedChangedVal == cty.NilVal: - // this should never happen without ApplyPath errors above - panic("requires replace path returned 2 nil values") - case priorChangedVal == cty.NilVal: - priorChangedVal = cty.NullVal(plannedChangedVal.Type()) - case plannedChangedVal == cty.NilVal: - plannedChangedVal = cty.NullVal(priorChangedVal.Type()) - } - - // Unmark for this value for the equality test. If only sensitivity has changed, - // this does not require an Update or Replace - unmarkedPlannedChangedVal, _ := plannedChangedVal.UnmarkDeep() - eqV := unmarkedPlannedChangedVal.Equals(priorChangedVal) - if !eqV.IsKnown() || eqV.False() { - reqRep.Add(path) - } - } - if diags.HasErrors() { - return plan, state, keyData, diags - } - } - - // The user might also ask us to force replacing a particular resource - // instance, regardless of whether the provider thinks it needs replacing. - // For example, users typically do this if they learn a particular object - // has become degraded in an immutable infrastructure scenario and so - // replacing it with a new object is a viable repair path. - matchedForceReplace := false - for _, candidateAddr := range forceReplace { - if candidateAddr.Equal(n.Addr) { - matchedForceReplace = true - break - } - - // For "force replace" purposes we require an exact resource instance - // address to match. If a user forgets to include the instance key - // for a multi-instance resource then it won't match here, but we - // have an earlier check in NodePlannableResource.Execute that should - // prevent us from getting here in that case. - } - - // Unmark for this test for value equality. - eqV := unmarkedPlannedNewVal.Equals(unmarkedPriorVal) - eq := eqV.IsKnown() && eqV.True() - - var action plans.Action - var actionReason plans.ResourceInstanceChangeActionReason - switch { - case priorVal.IsNull(): - action = plans.Create - case eq && !matchedForceReplace: - action = plans.NoOp - case matchedForceReplace || !reqRep.Empty(): - // If the user "forced replace" of this instance of if there are any - // "requires replace" paths left _after our filtering above_ then this - // is a replace action. - if createBeforeDestroy { - action = plans.CreateThenDelete - } else { - action = plans.DeleteThenCreate - } - switch { - case matchedForceReplace: - actionReason = plans.ResourceInstanceReplaceByRequest - case !reqRep.Empty(): - actionReason = plans.ResourceInstanceReplaceBecauseCannotUpdate - } - default: - action = plans.Update - // "Delete" is never chosen here, because deletion plans are always - // created more directly elsewhere, such as in "orphan" handling. - } - - if action.IsReplace() { - // In this strange situation we want to produce a change object that - // shows our real prior object but has a _new_ object that is built - // from a null prior object, since we're going to delete the one - // that has all the computed values on it. - // - // Therefore we'll ask the provider to plan again here, giving it - // a null object for the prior, and then we'll meld that with the - // _actual_ prior state to produce a correctly-shaped replace change. - // The resulting change should show any computed attributes changing - // from known prior values to unknown values, unless the provider is - // able to predict new values for any of these computed attributes. - nullPriorVal := cty.NullVal(schema.ImpliedType()) - - // Since there is no prior state to compare after replacement, we need - // a new unmarked config from our original with no ignored values. - unmarkedConfigVal := origConfigVal - if origConfigVal.ContainsMarked() { - unmarkedConfigVal, _ = origConfigVal.UnmarkDeep() - } - - // create a new proposed value from the null state and the config - proposedNewVal = objchange.ProposedNew(schema, nullPriorVal, unmarkedConfigVal) - - resp = provider.PlanResourceChange(providers.PlanResourceChangeRequest{ - TypeName: n.Addr.Resource.Resource.Type, - Config: unmarkedConfigVal, - PriorState: nullPriorVal, - ProposedNewState: proposedNewVal, - PriorPrivate: plannedPrivate, - ProviderMeta: metaConfigVal, - }) - // We need to tread carefully here, since if there are any warnings - // in here they probably also came out of our previous call to - // PlanResourceChange above, and so we don't want to repeat them. - // Consequently, we break from the usual pattern here and only - // append these new diagnostics if there's at least one error inside. - if resp.Diagnostics.HasErrors() { - diags = diags.Append(resp.Diagnostics.InConfigBody(config.Config, n.Addr.String())) - return plan, state, keyData, diags - } - plannedNewVal = resp.PlannedState - plannedPrivate = resp.PlannedPrivate - - if len(unmarkedPaths) > 0 { - plannedNewVal = plannedNewVal.MarkWithPaths(unmarkedPaths) - } - - for _, err := range plannedNewVal.Type().TestConformance(schema.ImpliedType()) { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Provider produced invalid plan", - fmt.Sprintf( - "Provider %q planned an invalid value for %s%s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.", - n.ResolvedProvider.Provider, n.Addr, tfdiags.FormatError(err), - ), - )) - } - if diags.HasErrors() { - return plan, state, keyData, diags - } - } - - // If our prior value was tainted then we actually want this to appear - // as a replace change, even though so far we've been treating it as a - // create. - if action == plans.Create && !priorValTainted.IsNull() { - if createBeforeDestroy { - action = plans.CreateThenDelete - } else { - action = plans.DeleteThenCreate - } - priorVal = priorValTainted - actionReason = plans.ResourceInstanceReplaceBecauseTainted - } - - // If we plan to write or delete sensitive paths from state, - // this is an Update action - if action == plans.NoOp && !marksEqual(unmarkedPaths, priorPaths) { - action = plans.Update - } - - // As a special case, if we have a previous diff (presumably from the plan - // phases, whereas we're now in the apply phase) and it was for a replace, - // we've already deleted the original object from state by the time we - // get here and so we would've ended up with a _create_ action this time, - // which we now need to paper over to get a result consistent with what - // we originally intended. - if plannedChange != nil { - prevChange := *plannedChange - if prevChange.Action.IsReplace() && action == plans.Create { - log.Printf("[TRACE] plan: %s treating Create change as %s change to match with earlier plan", n.Addr, prevChange.Action) - action = prevChange.Action - priorVal = prevChange.Before - } - } - - // Call post-refresh hook - diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) { - return h.PostDiff(n.Addr, states.CurrentGen, action, priorVal, plannedNewVal) - })) - if diags.HasErrors() { - return plan, state, keyData, diags - } - - // Update our return plan - plan = &plans.ResourceInstanceChange{ - Addr: n.Addr, - PrevRunAddr: n.prevRunAddr(ctx), - Private: plannedPrivate, - ProviderAddr: n.ResolvedProvider, - Change: plans.Change{ - Action: action, - Before: priorVal, - // Pass the marked planned value through in our change - // to propogate through evaluation. - // Marks will be removed when encoding. - After: plannedNewVal, - }, - ActionReason: actionReason, - RequiredReplace: reqRep, - } - - // Update our return state - state = &states.ResourceInstanceObject{ - // We use the special "planned" status here to note that this - // object's value is not yet complete. Objects with this status - // cannot be used during expression evaluation, so the caller - // must _also_ record the returned change in the active plan, - // which the expression evaluator will use in preference to this - // incomplete value recorded in the state. - Status: states.ObjectPlanned, - Value: plannedNewVal, - Private: plannedPrivate, - } - - return plan, state, keyData, diags -} - -func (n *NodeAbstractResource) processIgnoreChanges(prior, config cty.Value, schema *configschema.Block) (cty.Value, tfdiags.Diagnostics) { - // ignore_changes only applies when an object already exists, since we - // can't ignore changes to a thing we've not created yet. - if prior.IsNull() { - return config, nil - } - - ignoreChanges := traversalsToPaths(n.Config.Managed.IgnoreChanges) - ignoreAll := n.Config.Managed.IgnoreAllChanges - - if len(ignoreChanges) == 0 && !ignoreAll { - return config, nil - } - - if ignoreAll { - // Legacy providers need up to clean up their invalid plans and ensure - // no changes are passed though, but that also means making an invalid - // config with computed values. In that case we just don't supply a - // schema and return the prior val directly. - if schema == nil { - return prior, nil - } - - // If we are trying to ignore all attribute changes, we must filter - // computed attributes out from the prior state to avoid sending them - // to the provider as if they were included in the configuration. - ret, _ := cty.Transform(prior, func(path cty.Path, v cty.Value) (cty.Value, error) { - attr := schema.AttributeByPath(path) - if attr != nil && attr.Computed && !attr.Optional { - return cty.NullVal(v.Type()), nil - } - - return v, nil - }) - - return ret, nil - } - - if prior.IsNull() || config.IsNull() { - // Ignore changes doesn't apply when we're creating for the first time. - // Proposed should never be null here, but if it is then we'll just let it be. - return config, nil - } - - ret, diags := processIgnoreChangesIndividual(prior, config, ignoreChanges) - - return ret, diags -} - -// Convert the hcl.Traversal values we get form the configuration to the -// cty.Path values we need to operate on the cty.Values -func traversalsToPaths(traversals []hcl.Traversal) []cty.Path { - paths := make([]cty.Path, len(traversals)) - for i, traversal := range traversals { - path := traversalToPath(traversal) - paths[i] = path - } - return paths -} - -func traversalToPath(traversal hcl.Traversal) cty.Path { - path := make(cty.Path, len(traversal)) - for si, step := range traversal { - switch ts := step.(type) { - case hcl.TraverseRoot: - path[si] = cty.GetAttrStep{ - Name: ts.Name, - } - case hcl.TraverseAttr: - path[si] = cty.GetAttrStep{ - Name: ts.Name, - } - case hcl.TraverseIndex: - path[si] = cty.IndexStep{ - Key: ts.Key, - } - default: - panic(fmt.Sprintf("unsupported traversal step %#v", step)) - } - } - return path -} - -func processIgnoreChangesIndividual(prior, config cty.Value, ignoreChangesPath []cty.Path) (cty.Value, tfdiags.Diagnostics) { - type ignoreChange struct { - // Path is the full path, minus any trailing map index - path cty.Path - // Value is the value we are to retain at the above path. If there is a - // key value, this must be a map and the desired value will be at the - // key index. - value cty.Value - // Key is the index key if the ignored path ends in a map index. - key cty.Value - } - var ignoredValues []ignoreChange - - // Find the actual changes first and store them in the ignoreChange struct. - // If the change was to a map value, and the key doesn't exist in the - // config, it would never be visited in the transform walk. - for _, icPath := range ignoreChangesPath { - key := cty.NullVal(cty.String) - // check for a map index, since maps are the only structure where we - // could have invalid path steps. - last, ok := icPath[len(icPath)-1].(cty.IndexStep) - if ok { - if last.Key.Type() == cty.String { - icPath = icPath[:len(icPath)-1] - key = last.Key - } - } - - // The structure should have been validated already, and we already - // trimmed the trailing map index. Any other intermediate index error - // means we wouldn't be able to apply the value below, so no need to - // record this. - p, err := icPath.Apply(prior) - if err != nil { - continue - } - c, err := icPath.Apply(config) - if err != nil { - continue - } - - // If this is a map, it is checking the entire map value for equality - // rather than the individual key. This means that the change is stored - // here even if our ignored key doesn't change. That is OK since it - // won't cause any changes in the transformation, but allows us to skip - // breaking up the maps and checking for key existence here too. - if !p.RawEquals(c) { - // there a change to ignore at this path, store the prior value - ignoredValues = append(ignoredValues, ignoreChange{icPath, p, key}) - } - } - - if len(ignoredValues) == 0 { - return config, nil - } - - ret, _ := cty.Transform(config, func(path cty.Path, v cty.Value) (cty.Value, error) { - // Easy path for when we are only matching the entire value. The only - // values we break up for inspection are maps. - if !v.Type().IsMapType() { - for _, ignored := range ignoredValues { - if path.Equals(ignored.path) { - return ignored.value, nil - } - } - return v, nil - } - // We now know this must be a map, so we need to accumulate the values - // key-by-key. - - if !v.IsNull() && !v.IsKnown() { - // since v is not known, we cannot ignore individual keys - return v, nil - } - - // The map values will remain as cty values, so we only need to store - // the marks from the outer map itself - v, vMarks := v.Unmark() - - // The configMap is the current configuration value, which we will - // mutate based on the ignored paths and the prior map value. - var configMap map[string]cty.Value - switch { - case v.IsNull() || v.LengthInt() == 0: - configMap = map[string]cty.Value{} - default: - configMap = v.AsValueMap() - } - - for _, ignored := range ignoredValues { - if !path.Equals(ignored.path) { - continue - } - - if ignored.key.IsNull() { - // The map address is confirmed to match at this point, - // so if there is no key, we want the entire map and can - // stop accumulating values. - return ignored.value, nil - } - // Now we know we are ignoring a specific index of this map, so get - // the config map and modify, add, or remove the desired key. - - // We also need to create a prior map, so we can check for - // existence while getting the value, because Value.Index will - // return null for a key with a null value and for a non-existent - // key. - var priorMap map[string]cty.Value - - // We need to drop the marks from the ignored map for handling. We - // don't need to store these, as we now know the ignored value is - // only within the map, not the map itself. - ignoredVal, _ := ignored.value.Unmark() - - switch { - case ignored.value.IsNull() || ignoredVal.LengthInt() == 0: - priorMap = map[string]cty.Value{} - default: - priorMap = ignoredVal.AsValueMap() - } - - key := ignored.key.AsString() - priorElem, keep := priorMap[key] - - switch { - case !keep: - // this didn't exist in the old map value, so we're keeping the - // "absence" of the key by removing it from the config - delete(configMap, key) - default: - configMap[key] = priorElem - } - } - - var newVal cty.Value - switch { - case len(configMap) > 0: - newVal = cty.MapVal(configMap) - case v.IsNull(): - // if the config value was null, and no values remain in the map, - // reset the value to null. - newVal = v - default: - newVal = cty.MapValEmpty(v.Type().ElementType()) - } - - if len(vMarks) > 0 { - newVal = newVal.WithMarks(vMarks) - } - - return newVal, nil - }) - return ret, nil -} - -// readDataSource handles everything needed to call ReadDataSource on the provider. -// A previously evaluated configVal can be passed in, or a new one is generated -// from the resource configuration. -func (n *NodeAbstractResourceInstance) readDataSource(ctx EvalContext, configVal cty.Value) (cty.Value, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - var newVal cty.Value - - config := *n.Config - - provider, providerSchema, err := getProvider(ctx, n.ResolvedProvider) - diags = diags.Append(err) - if diags.HasErrors() { - return newVal, diags - } - if providerSchema == nil { - diags = diags.Append(fmt.Errorf("provider schema not available for %s", n.Addr)) - return newVal, diags - } - schema, _ := providerSchema.SchemaForResourceAddr(n.Addr.ContainingResource().Resource) - if schema == nil { - // Should be caught during validation, so we don't bother with a pretty error here - diags = diags.Append(fmt.Errorf("provider %q does not support data source %q", n.ResolvedProvider, n.Addr.ContainingResource().Resource.Type)) - return newVal, diags - } - - metaConfigVal, metaDiags := n.providerMetas(ctx) - diags = diags.Append(metaDiags) - if diags.HasErrors() { - return newVal, diags - } - - // Unmark before sending to provider, will re-mark before returning - var pvm []cty.PathValueMarks - configVal, pvm = configVal.UnmarkDeepWithPaths() - - log.Printf("[TRACE] readDataSource: Re-validating config for %s", n.Addr) - validateResp := provider.ValidateDataResourceConfig( - providers.ValidateDataResourceConfigRequest{ - TypeName: n.Addr.ContainingResource().Resource.Type, - Config: configVal, - }, - ) - diags = diags.Append(validateResp.Diagnostics.InConfigBody(config.Config, n.Addr.String())) - if diags.HasErrors() { - return newVal, diags - } - - // If we get down here then our configuration is complete and we're read - // to actually call the provider to read the data. - log.Printf("[TRACE] readDataSource: %s configuration is complete, so reading from provider", n.Addr) - - diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) { - return h.PreApply(n.Addr, states.CurrentGen, plans.Read, cty.NullVal(configVal.Type()), configVal) - })) - if diags.HasErrors() { - return newVal, diags - } - - resp := provider.ReadDataSource(providers.ReadDataSourceRequest{ - TypeName: n.Addr.ContainingResource().Resource.Type, - Config: configVal, - ProviderMeta: metaConfigVal, - }) - diags = diags.Append(resp.Diagnostics.InConfigBody(config.Config, n.Addr.String())) - if diags.HasErrors() { - return newVal, diags - } - newVal = resp.State - if newVal == cty.NilVal { - // This can happen with incompletely-configured mocks. We'll allow it - // and treat it as an alias for a properly-typed null value. - newVal = cty.NullVal(schema.ImpliedType()) - } - - for _, err := range newVal.Type().TestConformance(schema.ImpliedType()) { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Provider produced invalid object", - fmt.Sprintf( - "Provider %q produced an invalid value for %s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.", - n.ResolvedProvider, tfdiags.FormatErrorPrefixed(err, n.Addr.String()), - ), - )) - } - if diags.HasErrors() { - return newVal, diags - } - - if newVal.IsNull() { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Provider produced null object", - fmt.Sprintf( - "Provider %q produced a null value for %s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.", - n.ResolvedProvider, n.Addr, - ), - )) - } - - if !newVal.IsNull() && !newVal.IsWhollyKnown() { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Provider produced invalid object", - fmt.Sprintf( - "Provider %q produced a value for %s that is not wholly known.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.", - n.ResolvedProvider, n.Addr, - ), - )) - - // We'll still save the object, but we need to eliminate any unknown - // values first because we can't serialize them in the state file. - // Note that this may cause set elements to be coalesced if they - // differed only by having unknown values, but we don't worry about - // that here because we're saving the value only for inspection - // purposes; the error we added above will halt the graph walk. - newVal = cty.UnknownAsNull(newVal) - } - - if len(pvm) > 0 { - newVal = newVal.MarkWithPaths(pvm) - } - - diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) { - return h.PostApply(n.Addr, states.CurrentGen, newVal, diags.Err()) - })) - - return newVal, diags -} - -func (n *NodeAbstractResourceInstance) providerMetas(ctx EvalContext) (cty.Value, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - metaConfigVal := cty.NullVal(cty.DynamicPseudoType) - - _, providerSchema, err := getProvider(ctx, n.ResolvedProvider) - if err != nil { - return metaConfigVal, diags.Append(err) - } - if providerSchema == nil { - return metaConfigVal, diags.Append(fmt.Errorf("provider schema not available for %s", n.Addr)) - } - if n.ProviderMetas != nil { - if m, ok := n.ProviderMetas[n.ResolvedProvider.Provider]; ok && m != nil { - // if the provider doesn't support this feature, throw an error - if providerSchema.ProviderMeta == nil { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: fmt.Sprintf("Provider %s doesn't support provider_meta", n.ResolvedProvider.Provider.String()), - Detail: fmt.Sprintf("The resource %s belongs to a provider that doesn't support provider_meta blocks", n.Addr.Resource), - Subject: &m.ProviderRange, - }) - } else { - var configDiags tfdiags.Diagnostics - metaConfigVal, _, configDiags = ctx.EvaluateBlock(m.Config, providerSchema.ProviderMeta, nil, EvalDataForNoInstanceKey) - diags = diags.Append(configDiags) - } - } - } - return metaConfigVal, diags -} - -// planDataSource deals with the main part of the data resource lifecycle: -// either actually reading from the data source or generating a plan to do so. -// -// currentState is the current state for the data source, and the new state is -// returned. While data sources are read-only, we need to start with the prior -// state to determine if we have a change or not. If we needed to read a new -// value, but it still matches the previous state, then we can record a NoNop -// change. If the states don't match then we record a Read change so that the -// new value is applied to the state. -func (n *NodeAbstractResourceInstance) planDataSource(ctx EvalContext, checkRuleSeverity tfdiags.Severity, skipPlanChanges bool) (*plans.ResourceInstanceChange, *states.ResourceInstanceObject, instances.RepetitionData, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - var keyData instances.RepetitionData - var configVal cty.Value - - _, providerSchema, err := getProvider(ctx, n.ResolvedProvider) - if err != nil { - return nil, nil, keyData, diags.Append(err) - } - if providerSchema == nil { - return nil, nil, keyData, diags.Append(fmt.Errorf("provider schema not available for %s", n.Addr)) - } - - config := *n.Config - schema, _ := providerSchema.SchemaForResourceAddr(n.Addr.ContainingResource().Resource) - if schema == nil { - // Should be caught during validation, so we don't bother with a pretty error here - diags = diags.Append(fmt.Errorf("provider %q does not support data source %q", n.ResolvedProvider, n.Addr.ContainingResource().Resource.Type)) - return nil, nil, keyData, diags - } - - objTy := schema.ImpliedType() - priorVal := cty.NullVal(objTy) - - forEach, _ := evaluateForEachExpression(config.ForEach, ctx) - keyData = EvalDataForInstanceKey(n.ResourceInstanceAddr().Resource.Key, forEach) - - checkDiags := evalCheckRules( - addrs.ResourcePrecondition, - n.Config.Preconditions, - ctx, n.Addr, keyData, - checkRuleSeverity, - ) - diags = diags.Append(checkDiags) - if diags.HasErrors() { - return nil, nil, keyData, diags // failed preconditions prevent further evaluation - } - - var configDiags tfdiags.Diagnostics - configVal, _, configDiags = ctx.EvaluateBlock(config.Config, schema, nil, keyData) - diags = diags.Append(configDiags) - if configDiags.HasErrors() { - return nil, nil, keyData, diags - } - - unmarkedConfigVal, configMarkPaths := configVal.UnmarkDeepWithPaths() - - configKnown := configVal.IsWhollyKnown() - depsPending := n.dependenciesHavePendingChanges(ctx) - // If our configuration contains any unknown values, or we depend on any - // unknown values then we must defer the read to the apply phase by - // producing a "Read" change for this resource, and a placeholder value for - // it in the state. - if depsPending || !configKnown { - // We can't plan any changes if we're only refreshing, so the only - // value we can set here is whatever was in state previously. - if skipPlanChanges { - plannedNewState := &states.ResourceInstanceObject{ - Value: priorVal, - Status: states.ObjectReady, - } - - return nil, plannedNewState, keyData, diags - } - - var reason plans.ResourceInstanceChangeActionReason - switch { - case !configKnown: - log.Printf("[TRACE] planDataSource: %s configuration not fully known yet, so deferring to apply phase", n.Addr) - reason = plans.ResourceInstanceReadBecauseConfigUnknown - case depsPending: - // NOTE: depsPending can be true at the same time as configKnown - // is false; configKnown takes precedence because it's more - // specific. - log.Printf("[TRACE] planDataSource: %s configuration is fully known, at least one dependency has changes pending", n.Addr) - reason = plans.ResourceInstanceReadBecauseDependencyPending - } - - proposedNewVal := objchange.PlannedDataResourceObject(schema, unmarkedConfigVal) - proposedNewVal = proposedNewVal.MarkWithPaths(configMarkPaths) - - // Apply detects that the data source will need to be read by the After - // value containing unknowns from PlanDataResourceObject. - plannedChange := &plans.ResourceInstanceChange{ - Addr: n.Addr, - PrevRunAddr: n.prevRunAddr(ctx), - ProviderAddr: n.ResolvedProvider, - Change: plans.Change{ - Action: plans.Read, - Before: priorVal, - After: proposedNewVal, - }, - ActionReason: reason, - } - - plannedNewState := &states.ResourceInstanceObject{ - Value: proposedNewVal, - Status: states.ObjectPlanned, - } - - diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) { - return h.PostDiff(n.Addr, states.CurrentGen, plans.Read, priorVal, proposedNewVal) - })) - - return plannedChange, plannedNewState, keyData, diags - } - - // We have a complete configuration with no dependencies to wait on, so we - // can read the data source into the state. - newVal, readDiags := n.readDataSource(ctx, configVal) - diags = diags.Append(readDiags) - if diags.HasErrors() { - return nil, nil, keyData, diags - } - - plannedNewState := &states.ResourceInstanceObject{ - Value: newVal, - Status: states.ObjectReady, - } - - return nil, plannedNewState, keyData, diags -} - -// dependenciesHavePendingChanges determines whether any managed resource the -// receiver depends on has a change pending in the plan, in which case we'd -// need to override the usual behavior of immediately reading from the data -// source where possible, and instead defer the read until the apply step. -func (n *NodeAbstractResourceInstance) dependenciesHavePendingChanges(ctx EvalContext) bool { - nModInst := n.Addr.Module - nMod := nModInst.Module() - - // Check and see if any depends_on dependencies have - // changes, since they won't show up as changes in the - // configuration. - changes := ctx.Changes() - - depsToUse := n.dependsOn - - if n.Addr.Resource.Resource.Mode == addrs.DataResourceMode { - if n.Config.HasCustomConditions() { - // For a data resource with custom conditions we need to look at - // the full set of resource dependencies -- both direct and - // indirect -- because an upstream update might be what's needed - // in order to make a condition pass. - depsToUse = n.Dependencies - } - } - - for _, d := range depsToUse { - if d.Resource.Mode == addrs.DataResourceMode { - // Data sources have no external side effects, so they pose a need - // to delay this read. If they do have a change planned, it must be - // because of a dependency on a managed resource, in which case - // we'll also encounter it in this list of dependencies. - continue - } - - for _, change := range changes.GetChangesForConfigResource(d) { - changeModInst := change.Addr.Module - changeMod := changeModInst.Module() - - if changeMod.Equal(nMod) && !changeModInst.Equal(nModInst) { - // Dependencies are tracked by configuration address, which - // means we may have changes from other instances of parent - // modules. The actual reference can only take effect within - // the same module instance, so skip any that aren't an exact - // match - continue - } - - if change != nil && change.Action != plans.NoOp { - return true - } - } - } - return false -} - -// apply deals with the main part of the data resource lifecycle: either -// actually reading from the data source or generating a plan to do so. -func (n *NodeAbstractResourceInstance) applyDataSource(ctx EvalContext, planned *plans.ResourceInstanceChange) (*states.ResourceInstanceObject, instances.RepetitionData, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - var keyData instances.RepetitionData - - _, providerSchema, err := getProvider(ctx, n.ResolvedProvider) - if err != nil { - return nil, keyData, diags.Append(err) - } - if providerSchema == nil { - return nil, keyData, diags.Append(fmt.Errorf("provider schema not available for %s", n.Addr)) - } - - if planned != nil && planned.Action != plans.Read && planned.Action != plans.NoOp { - // If any other action gets in here then that's always a bug; this - // EvalNode only deals with reading. - diags = diags.Append(fmt.Errorf( - "invalid action %s for %s: only Read is supported (this is a bug in Terraform; please report it!)", - planned.Action, n.Addr, - )) - return nil, keyData, diags - } - - config := *n.Config - schema, _ := providerSchema.SchemaForResourceAddr(n.Addr.ContainingResource().Resource) - if schema == nil { - // Should be caught during validation, so we don't bother with a pretty error here - diags = diags.Append(fmt.Errorf("provider %q does not support data source %q", n.ResolvedProvider, n.Addr.ContainingResource().Resource.Type)) - return nil, keyData, diags - } - - forEach, _ := evaluateForEachExpression(config.ForEach, ctx) - keyData = EvalDataForInstanceKey(n.Addr.Resource.Key, forEach) - - checkDiags := evalCheckRules( - addrs.ResourcePrecondition, - n.Config.Preconditions, - ctx, n.Addr, keyData, - tfdiags.Error, - ) - diags = diags.Append(checkDiags) - if diags.HasErrors() { - diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) { - return h.PostApply(n.Addr, states.CurrentGen, planned.Before, diags.Err()) - })) - return nil, keyData, diags // failed preconditions prevent further evaluation - } - - if planned.Action == plans.NoOp { - // If we didn't actually plan to read this then we have nothing more - // to do; we're evaluating this only for incidentals like the - // precondition/postcondition checks. - return nil, keyData, diags - } - - configVal, _, configDiags := ctx.EvaluateBlock(config.Config, schema, nil, keyData) - diags = diags.Append(configDiags) - if configDiags.HasErrors() { - return nil, keyData, diags - } - - newVal, readDiags := n.readDataSource(ctx, configVal) - diags = diags.Append(readDiags) - if diags.HasErrors() { - return nil, keyData, diags - } - - state := &states.ResourceInstanceObject{ - Value: newVal, - Status: states.ObjectReady, - } - - return state, keyData, diags -} - -// evalApplyProvisioners determines if provisioners need to be run, and if so -// executes the provisioners for a resource and returns an updated error if -// provisioning fails. -func (n *NodeAbstractResourceInstance) evalApplyProvisioners(ctx EvalContext, state *states.ResourceInstanceObject, createNew bool, when configs.ProvisionerWhen) tfdiags.Diagnostics { - var diags tfdiags.Diagnostics - - if state == nil { - log.Printf("[TRACE] evalApplyProvisioners: %s has no state, so skipping provisioners", n.Addr) - return nil - } - if when == configs.ProvisionerWhenCreate && !createNew { - // If we're not creating a new resource, then don't run provisioners - log.Printf("[TRACE] evalApplyProvisioners: %s is not freshly-created, so no provisioning is required", n.Addr) - return nil - } - if state.Status == states.ObjectTainted { - // No point in provisioning an object that is already tainted, since - // it's going to get recreated on the next apply anyway. - log.Printf("[TRACE] evalApplyProvisioners: %s is tainted, so skipping provisioning", n.Addr) - return nil - } - - provs := filterProvisioners(n.Config, when) - if len(provs) == 0 { - // We have no provisioners, so don't do anything - return nil - } - - // Call pre hook - diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) { - return h.PreProvisionInstance(n.Addr, state.Value) - })) - if diags.HasErrors() { - return diags - } - - // If there are no errors, then we append it to our output error - // if we have one, otherwise we just output it. - diags = diags.Append(n.applyProvisioners(ctx, state, when, provs)) - if diags.HasErrors() { - log.Printf("[TRACE] evalApplyProvisioners: %s provisioning failed, but we will continue anyway at the caller's request", n.Addr) - return diags - } - - // Call post hook - return diags.Append(ctx.Hook(func(h Hook) (HookAction, error) { - return h.PostProvisionInstance(n.Addr, state.Value) - })) -} - -// filterProvisioners filters the provisioners on the resource to only -// the provisioners specified by the "when" option. -func filterProvisioners(config *configs.Resource, when configs.ProvisionerWhen) []*configs.Provisioner { - // Fast path the zero case - if config == nil || config.Managed == nil { - return nil - } - - if len(config.Managed.Provisioners) == 0 { - return nil - } - - result := make([]*configs.Provisioner, 0, len(config.Managed.Provisioners)) - for _, p := range config.Managed.Provisioners { - if p.When == when { - result = append(result, p) - } - } - - return result -} - -// applyProvisioners executes the provisioners for a resource. -func (n *NodeAbstractResourceInstance) applyProvisioners(ctx EvalContext, state *states.ResourceInstanceObject, when configs.ProvisionerWhen, provs []*configs.Provisioner) tfdiags.Diagnostics { - var diags tfdiags.Diagnostics - - // this self is only used for destroy provisioner evaluation, and must - // refer to the last known value of the resource. - self := state.Value - - var evalScope func(EvalContext, hcl.Body, cty.Value, *configschema.Block) (cty.Value, tfdiags.Diagnostics) - switch when { - case configs.ProvisionerWhenDestroy: - evalScope = n.evalDestroyProvisionerConfig - default: - evalScope = n.evalProvisionerConfig - } - - // If there's a connection block defined directly inside the resource block - // then it'll serve as a base connection configuration for all of the - // provisioners. - var baseConn hcl.Body - if n.Config.Managed != nil && n.Config.Managed.Connection != nil { - baseConn = n.Config.Managed.Connection.Config - } - - for _, prov := range provs { - log.Printf("[TRACE] applyProvisioners: provisioning %s with %q", n.Addr, prov.Type) - - // Get the provisioner - provisioner, err := ctx.Provisioner(prov.Type) - if err != nil { - return diags.Append(err) - } - - schema, err := ctx.ProvisionerSchema(prov.Type) - if err != nil { - // This error probably won't be a great diagnostic, but in practice - // we typically catch this problem long before we get here, so - // it should be rare to return via this codepath. - diags = diags.Append(err) - return diags - } - - config, configDiags := evalScope(ctx, prov.Config, self, schema) - diags = diags.Append(configDiags) - if diags.HasErrors() { - return diags - } - - // If the provisioner block contains a connection block of its own then - // it can override the base connection configuration, if any. - var localConn hcl.Body - if prov.Connection != nil { - localConn = prov.Connection.Config - } - - var connBody hcl.Body - switch { - case baseConn != nil && localConn != nil: - // Our standard merging logic applies here, similar to what we do - // with _override.tf configuration files: arguments from the - // base connection block will be masked by any arguments of the - // same name in the local connection block. - connBody = configs.MergeBodies(baseConn, localConn) - case baseConn != nil: - connBody = baseConn - case localConn != nil: - connBody = localConn - } - - // start with an empty connInfo - connInfo := cty.NullVal(connectionBlockSupersetSchema.ImpliedType()) - - if connBody != nil { - var connInfoDiags tfdiags.Diagnostics - connInfo, connInfoDiags = evalScope(ctx, connBody, self, connectionBlockSupersetSchema) - diags = diags.Append(connInfoDiags) - if diags.HasErrors() { - return diags - } - } - - { - // Call pre hook - err := ctx.Hook(func(h Hook) (HookAction, error) { - return h.PreProvisionInstanceStep(n.Addr, prov.Type) - }) - if err != nil { - return diags.Append(err) - } - } - - // The output function - outputFn := func(msg string) { - ctx.Hook(func(h Hook) (HookAction, error) { - h.ProvisionOutput(n.Addr, prov.Type, msg) - return HookActionContinue, nil - }) - } - - // If our config or connection info contains any marked values, ensure - // those are stripped out before sending to the provisioner. Unlike - // resources, we have no need to capture the marked paths and reapply - // later. - unmarkedConfig, configMarks := config.UnmarkDeep() - unmarkedConnInfo, _ := connInfo.UnmarkDeep() - - // Marks on the config might result in leaking sensitive values through - // provisioner logging, so we conservatively suppress all output in - // this case. This should not apply to connection info values, which - // provisioners ought not to be logging anyway. - if len(configMarks) > 0 { - outputFn = func(msg string) { - ctx.Hook(func(h Hook) (HookAction, error) { - h.ProvisionOutput(n.Addr, prov.Type, "(output suppressed due to sensitive value in config)") - return HookActionContinue, nil - }) - } - } - - output := CallbackUIOutput{OutputFn: outputFn} - resp := provisioner.ProvisionResource(provisioners.ProvisionResourceRequest{ - Config: unmarkedConfig, - Connection: unmarkedConnInfo, - UIOutput: &output, - }) - applyDiags := resp.Diagnostics.InConfigBody(prov.Config, n.Addr.String()) - - // Call post hook - hookErr := ctx.Hook(func(h Hook) (HookAction, error) { - return h.PostProvisionInstanceStep(n.Addr, prov.Type, applyDiags.Err()) - }) - - switch prov.OnFailure { - case configs.ProvisionerOnFailureContinue: - if applyDiags.HasErrors() { - log.Printf("[WARN] Errors while provisioning %s with %q, but continuing as requested in configuration", n.Addr, prov.Type) - } else { - // Maybe there are warnings that we still want to see - diags = diags.Append(applyDiags) - } - default: - diags = diags.Append(applyDiags) - if applyDiags.HasErrors() { - log.Printf("[WARN] Errors while provisioning %s with %q, so aborting", n.Addr, prov.Type) - return diags - } - } - - // Deal with the hook - if hookErr != nil { - return diags.Append(hookErr) - } - } - - return diags -} - -func (n *NodeAbstractResourceInstance) evalProvisionerConfig(ctx EvalContext, body hcl.Body, self cty.Value, schema *configschema.Block) (cty.Value, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - - forEach, forEachDiags := evaluateForEachExpression(n.Config.ForEach, ctx) - diags = diags.Append(forEachDiags) - - keyData := EvalDataForInstanceKey(n.ResourceInstanceAddr().Resource.Key, forEach) - - config, _, configDiags := ctx.EvaluateBlock(body, schema, n.ResourceInstanceAddr().Resource, keyData) - diags = diags.Append(configDiags) - - return config, diags -} - -// during destroy a provisioner can only evaluate within the scope of the parent resource -func (n *NodeAbstractResourceInstance) evalDestroyProvisionerConfig(ctx EvalContext, body hcl.Body, self cty.Value, schema *configschema.Block) (cty.Value, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - - // For a destroy-time provisioner forEach is intentionally nil here, - // which EvalDataForInstanceKey responds to by not populating EachValue - // in its result. That's okay because each.value is prohibited for - // destroy-time provisioners. - keyData := EvalDataForInstanceKey(n.ResourceInstanceAddr().Resource.Key, nil) - - evalScope := ctx.EvaluationScope(n.ResourceInstanceAddr().Resource, keyData) - config, evalDiags := evalScope.EvalSelfBlock(body, self, schema, keyData) - diags = diags.Append(evalDiags) - - return config, diags -} - -// apply accepts an applyConfig, instead of using n.Config, so destroy plans can -// send a nil config. The keyData information can be empty if the config is -// nil, since it is only used to evaluate the configuration. -func (n *NodeAbstractResourceInstance) apply( - ctx EvalContext, - state *states.ResourceInstanceObject, - change *plans.ResourceInstanceChange, - applyConfig *configs.Resource, - keyData instances.RepetitionData, - createBeforeDestroy bool) (*states.ResourceInstanceObject, tfdiags.Diagnostics) { - - var diags tfdiags.Diagnostics - if state == nil { - state = &states.ResourceInstanceObject{} - } - - if change.Action == plans.NoOp { - // If this is a no-op change then we don't want to actually change - // anything, so we'll just echo back the state we were given and - // let our internal checks and updates proceed. - log.Printf("[TRACE] NodeAbstractResourceInstance.apply: skipping %s because it has no planned action", n.Addr) - return state, diags - } - - provider, providerSchema, err := getProvider(ctx, n.ResolvedProvider) - if err != nil { - return nil, diags.Append(err) - } - schema, _ := providerSchema.SchemaForResourceType(n.Addr.Resource.Resource.Mode, n.Addr.Resource.Resource.Type) - if schema == nil { - // Should be caught during validation, so we don't bother with a pretty error here - diags = diags.Append(fmt.Errorf("provider does not support resource type %q", n.Addr.Resource.Resource.Type)) - return nil, diags - } - - log.Printf("[INFO] Starting apply for %s", n.Addr) - - configVal := cty.NullVal(cty.DynamicPseudoType) - if applyConfig != nil { - var configDiags tfdiags.Diagnostics - configVal, _, configDiags = ctx.EvaluateBlock(applyConfig.Config, schema, nil, keyData) - diags = diags.Append(configDiags) - if configDiags.HasErrors() { - return nil, diags - } - } - - if !configVal.IsWhollyKnown() { - // We don't have a pretty format function for a path, but since this is - // such a rare error, we can just drop the raw GoString values in here - // to make sure we have something to debug with. - var unknownPaths []string - cty.Transform(configVal, func(p cty.Path, v cty.Value) (cty.Value, error) { - if !v.IsKnown() { - unknownPaths = append(unknownPaths, fmt.Sprintf("%#v", p)) - } - return v, nil - }) - - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Configuration contains unknown value", - fmt.Sprintf("configuration for %s still contains unknown values during apply (this is a bug in Terraform; please report it!)\n"+ - "The following paths in the resource configuration are unknown:\n%s", - n.Addr, - strings.Join(unknownPaths, "\n"), - ), - )) - return nil, diags - } - - metaConfigVal, metaDiags := n.providerMetas(ctx) - diags = diags.Append(metaDiags) - if diags.HasErrors() { - return nil, diags - } - - log.Printf("[DEBUG] %s: applying the planned %s change", n.Addr, change.Action) - - // If our config, Before or After value contain any marked values, - // ensure those are stripped out before sending - // this to the provider - unmarkedConfigVal, _ := configVal.UnmarkDeep() - unmarkedBefore, beforePaths := change.Before.UnmarkDeepWithPaths() - unmarkedAfter, afterPaths := change.After.UnmarkDeepWithPaths() - - // If we have an Update action, our before and after values are equal, - // and only differ on their sensitivity, the newVal is the after val - // and we should not communicate with the provider. We do need to update - // the state with this new value, to ensure the sensitivity change is - // persisted. - eqV := unmarkedBefore.Equals(unmarkedAfter) - eq := eqV.IsKnown() && eqV.True() - if change.Action == plans.Update && eq && !marksEqual(beforePaths, afterPaths) { - // Copy the previous state, changing only the value - newState := &states.ResourceInstanceObject{ - CreateBeforeDestroy: state.CreateBeforeDestroy, - Dependencies: state.Dependencies, - Private: state.Private, - Status: state.Status, - Value: change.After, - } - return newState, diags - } - - resp := provider.ApplyResourceChange(providers.ApplyResourceChangeRequest{ - TypeName: n.Addr.Resource.Resource.Type, - PriorState: unmarkedBefore, - Config: unmarkedConfigVal, - PlannedState: unmarkedAfter, - PlannedPrivate: change.Private, - ProviderMeta: metaConfigVal, - }) - applyDiags := resp.Diagnostics - if applyConfig != nil { - applyDiags = applyDiags.InConfigBody(applyConfig.Config, n.Addr.String()) - } - diags = diags.Append(applyDiags) - - // Even if there are errors in the returned diagnostics, the provider may - // have returned a _partial_ state for an object that already exists but - // failed to fully configure, and so the remaining code must always run - // to completion but must be defensive against the new value being - // incomplete. - newVal := resp.NewState - - // If we have paths to mark, mark those on this new value - if len(afterPaths) > 0 { - newVal = newVal.MarkWithPaths(afterPaths) - } - - if newVal == cty.NilVal { - // Providers are supposed to return a partial new value even when errors - // occur, but sometimes they don't and so in that case we'll patch that up - // by just using the prior state, so we'll at least keep track of the - // object for the user to retry. - newVal = change.Before - - // As a special case, we'll set the new value to null if it looks like - // we were trying to execute a delete, because the provider in this case - // probably left the newVal unset intending it to be interpreted as "null". - if change.After.IsNull() { - newVal = cty.NullVal(schema.ImpliedType()) - } - - if !diags.HasErrors() { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Provider produced invalid object", - fmt.Sprintf( - "Provider %q produced an invalid nil value after apply for %s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.", - n.ResolvedProvider.String(), n.Addr.String(), - ), - )) - } - } - - var conformDiags tfdiags.Diagnostics - for _, err := range newVal.Type().TestConformance(schema.ImpliedType()) { - conformDiags = conformDiags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Provider produced invalid object", - fmt.Sprintf( - "Provider %q produced an invalid value after apply for %s. The result cannot not be saved in the Terraform state.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.", - n.ResolvedProvider.String(), tfdiags.FormatErrorPrefixed(err, n.Addr.String()), - ), - )) - } - diags = diags.Append(conformDiags) - if conformDiags.HasErrors() { - // Bail early in this particular case, because an object that doesn't - // conform to the schema can't be saved in the state anyway -- the - // serializer will reject it. - return nil, diags - } - - // After this point we have a type-conforming result object and so we - // must always run to completion to ensure it can be saved. If n.Error - // is set then we must not return a non-nil error, in order to allow - // evaluation to continue to a later point where our state object will - // be saved. - - // By this point there must not be any unknown values remaining in our - // object, because we've applied the change and we can't save unknowns - // in our persistent state. If any are present then we will indicate an - // error (which is always a bug in the provider) but we will also replace - // them with nulls so that we can successfully save the portions of the - // returned value that are known. - if !newVal.IsWhollyKnown() { - // To generate better error messages, we'll go for a walk through the - // value and make a separate diagnostic for each unknown value we - // find. - cty.Walk(newVal, func(path cty.Path, val cty.Value) (bool, error) { - if !val.IsKnown() { - pathStr := tfdiags.FormatCtyPath(path) - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Provider returned invalid result object after apply", - fmt.Sprintf( - "After the apply operation, the provider still indicated an unknown value for %s%s. All values must be known after apply, so this is always a bug in the provider and should be reported in the provider's own repository. Terraform will still save the other known object values in the state.", - n.Addr, pathStr, - ), - )) - } - return true, nil - }) - - // NOTE: This operation can potentially be lossy if there are multiple - // elements in a set that differ only by unknown values: after - // replacing with null these will be merged together into a single set - // element. Since we can only get here in the presence of a provider - // bug, we accept this because storing a result here is always a - // best-effort sort of thing. - newVal = cty.UnknownAsNull(newVal) - } - - if change.Action != plans.Delete && !diags.HasErrors() { - // Only values that were marked as unknown in the planned value are allowed - // to change during the apply operation. (We do this after the unknown-ness - // check above so that we also catch anything that became unknown after - // being known during plan.) - // - // If we are returning other errors anyway then we'll give this - // a pass since the other errors are usually the explanation for - // this one and so it's more helpful to let the user focus on the - // root cause rather than distract with this extra problem. - if errs := objchange.AssertObjectCompatible(schema, change.After, newVal); len(errs) > 0 { - if resp.LegacyTypeSystem { - // The shimming of the old type system in the legacy SDK is not precise - // enough to pass this consistency check, so we'll give it a pass here, - // but we will generate a warning about it so that we are more likely - // to notice in the logs if an inconsistency beyond the type system - // leads to a downstream provider failure. - var buf strings.Builder - fmt.Fprintf(&buf, "[WARN] Provider %q produced an unexpected new value for %s, but we are tolerating it because it is using the legacy plugin SDK.\n The following problems may be the cause of any confusing errors from downstream operations:", n.ResolvedProvider.String(), n.Addr) - for _, err := range errs { - fmt.Fprintf(&buf, "\n - %s", tfdiags.FormatError(err)) - } - log.Print(buf.String()) - - // The sort of inconsistency we won't catch here is if a known value - // in the plan is changed during apply. That can cause downstream - // problems because a dependent resource would make its own plan based - // on the planned value, and thus get a different result during the - // apply phase. This will usually lead to a "Provider produced invalid plan" - // error that incorrectly blames the downstream resource for the change. - - } else { - for _, err := range errs { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Provider produced inconsistent result after apply", - fmt.Sprintf( - "When applying changes to %s, provider %q produced an unexpected new value: %s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.", - n.Addr, n.ResolvedProvider.String(), tfdiags.FormatError(err), - ), - )) - } - } - } - } - - // If a provider returns a null or non-null object at the wrong time then - // we still want to save that but it often causes some confusing behaviors - // where it seems like Terraform is failing to take any action at all, - // so we'll generate some errors to draw attention to it. - if !diags.HasErrors() { - if change.Action == plans.Delete && !newVal.IsNull() { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Provider returned invalid result object after apply", - fmt.Sprintf( - "After applying a %s plan, the provider returned a non-null object for %s. Destroying should always produce a null value, so this is always a bug in the provider and should be reported in the provider's own repository. Terraform will still save this errant object in the state for debugging and recovery.", - change.Action, n.Addr, - ), - )) - } - if change.Action != plans.Delete && newVal.IsNull() { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Provider returned invalid result object after apply", - fmt.Sprintf( - "After applying a %s plan, the provider returned a null object for %s. Only destroying should always produce a null value, so this is always a bug in the provider and should be reported in the provider's own repository.", - change.Action, n.Addr, - ), - )) - } - } - - switch { - case diags.HasErrors() && newVal.IsNull(): - // Sometimes providers return a null value when an operation fails for - // some reason, but we'd rather keep the prior state so that the error - // can be corrected on a subsequent run. We must only do this for null - // new value though, or else we may discard partial updates the - // provider was able to complete. Otherwise, we'll continue using the - // prior state as the new value, making this effectively a no-op. If - // the item really _has_ been deleted then our next refresh will detect - // that and fix it up. - return state.DeepCopy(), diags - - case diags.HasErrors() && !newVal.IsNull(): - // if we have an error, make sure we restore the object status in the new state - newState := &states.ResourceInstanceObject{ - Status: state.Status, - Value: newVal, - Private: resp.Private, - CreateBeforeDestroy: createBeforeDestroy, - } - - // if the resource was being deleted, the dependencies are not going to - // be recalculated and we need to restore those as well. - if change.Action == plans.Delete { - newState.Dependencies = state.Dependencies - } - - return newState, diags - - case !newVal.IsNull(): - // Non error case with a new state - newState := &states.ResourceInstanceObject{ - Status: states.ObjectReady, - Value: newVal, - Private: resp.Private, - CreateBeforeDestroy: createBeforeDestroy, - } - return newState, diags - - default: - // Non error case, were the object was deleted - return nil, diags - } -} - -func (n *NodeAbstractResourceInstance) prevRunAddr(ctx EvalContext) addrs.AbsResourceInstance { - return resourceInstancePrevRunAddr(ctx, n.Addr) -} - -func resourceInstancePrevRunAddr(ctx EvalContext, currentAddr addrs.AbsResourceInstance) addrs.AbsResourceInstance { - table := ctx.MoveResults() - return table.OldAddr(currentAddr) -} diff --git a/internal/terraform/node_resource_abstract_instance_test.go b/internal/terraform/node_resource_abstract_instance_test.go deleted file mode 100644 index 22a5b0b5f766..000000000000 --- a/internal/terraform/node_resource_abstract_instance_test.go +++ /dev/null @@ -1,183 +0,0 @@ -package terraform - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/states" - "github.com/zclconf/go-cty/cty" -) - -func TestNodeAbstractResourceInstanceProvider(t *testing.T) { - tests := []struct { - Addr addrs.AbsResourceInstance - Config *configs.Resource - StoredProviderConfig addrs.AbsProviderConfig - Want addrs.Provider - }{ - { - Addr: addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "null_resource", - Name: "baz", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - Want: addrs.Provider{ - Hostname: addrs.DefaultProviderRegistryHost, - Namespace: "hashicorp", - Type: "null", - }, - }, - { - Addr: addrs.Resource{ - Mode: addrs.DataResourceMode, - Type: "terraform_remote_state", - Name: "baz", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - Want: addrs.Provider{ - // As a special case, the type prefix "terraform_" maps to - // the builtin provider, not the default one. - Hostname: addrs.BuiltInProviderHost, - Namespace: addrs.BuiltInProviderNamespace, - Type: "terraform", - }, - }, - { - Addr: addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "null_resource", - Name: "baz", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - Config: &configs.Resource{ - // Just enough configs.Resource for the Provider method. Not - // actually valid for general use. - Provider: addrs.Provider{ - Hostname: addrs.DefaultProviderRegistryHost, - Namespace: "awesomecorp", - Type: "happycloud", - }, - }, - // The config overrides the default behavior. - Want: addrs.Provider{ - Hostname: addrs.DefaultProviderRegistryHost, - Namespace: "awesomecorp", - Type: "happycloud", - }, - }, - { - Addr: addrs.Resource{ - Mode: addrs.DataResourceMode, - Type: "terraform_remote_state", - Name: "baz", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - Config: &configs.Resource{ - // Just enough configs.Resource for the Provider method. Not - // actually valid for general use. - Provider: addrs.Provider{ - Hostname: addrs.DefaultProviderRegistryHost, - Namespace: "awesomecorp", - Type: "happycloud", - }, - }, - // The config overrides the default behavior. - Want: addrs.Provider{ - Hostname: addrs.DefaultProviderRegistryHost, - Namespace: "awesomecorp", - Type: "happycloud", - }, - }, - { - Addr: addrs.Resource{ - Mode: addrs.DataResourceMode, - Type: "null_resource", - Name: "baz", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - Config: nil, - StoredProviderConfig: addrs.AbsProviderConfig{ - Module: addrs.RootModule, - Provider: addrs.Provider{ - Hostname: addrs.DefaultProviderRegistryHost, - Namespace: "awesomecorp", - Type: "null", - }, - }, - // The stored provider config overrides the default behavior. - Want: addrs.Provider{ - Hostname: addrs.DefaultProviderRegistryHost, - Namespace: "awesomecorp", - Type: "null", - }, - }, - } - - for _, test := range tests { - var name string - if test.Config != nil { - name = fmt.Sprintf("%s with configured %s", test.Addr, test.Config.Provider) - } else { - name = fmt.Sprintf("%s with no configuration", test.Addr) - } - t.Run(name, func(t *testing.T) { - node := &NodeAbstractResourceInstance{ - // Just enough NodeAbstractResourceInstance for the Provider - // function. (This would not be valid for some other functions.) - Addr: test.Addr, - NodeAbstractResource: NodeAbstractResource{ - Addr: test.Addr.ConfigResource(), - Config: test.Config, - storedProviderConfig: test.StoredProviderConfig, - }, - } - got := node.Provider() - if got != test.Want { - t.Errorf("wrong result\naddr: %s\nconfig: %#v\ngot: %s\nwant: %s", test.Addr, test.Config, got, test.Want) - } - }) - } -} - -func TestNodeAbstractResourceInstance_WriteResourceInstanceState(t *testing.T) { - state := states.NewState() - ctx := new(MockEvalContext) - ctx.StateState = state.SyncWrapper() - ctx.PathPath = addrs.RootModuleInstance - - mockProvider := mockProviderWithResourceTypeSchema("aws_instance", &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Optional: true, - }, - }, - }) - - obj := &states.ResourceInstanceObject{ - Value: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("i-abc123"), - }), - Status: states.ObjectReady, - } - - node := &NodeAbstractResourceInstance{ - Addr: mustResourceInstanceAddr("aws_instance.foo"), - // instanceState: obj, - NodeAbstractResource: NodeAbstractResource{ - ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - }, - } - ctx.ProviderProvider = mockProvider - ctx.ProviderSchemaSchema = mockProvider.ProviderSchema() - - err := node.writeResourceInstanceState(ctx, obj, workingState) - if err != nil { - t.Fatalf("unexpected error: %s", err.Error()) - } - - checkStateString(t, state, ` -aws_instance.foo: - ID = i-abc123 - provider = provider["registry.terraform.io/hashicorp/aws"] - `) -} diff --git a/internal/terraform/node_resource_abstract_test.go b/internal/terraform/node_resource_abstract_test.go deleted file mode 100644 index 51ad8d9698ed..000000000000 --- a/internal/terraform/node_resource_abstract_test.go +++ /dev/null @@ -1,312 +0,0 @@ -package terraform - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" - "github.com/zclconf/go-cty/cty" -) - -func TestNodeAbstractResourceProvider(t *testing.T) { - tests := []struct { - Addr addrs.ConfigResource - Config *configs.Resource - Want addrs.Provider - }{ - { - Addr: addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "null_resource", - Name: "baz", - }.InModule(addrs.RootModule), - Want: addrs.Provider{ - Hostname: addrs.DefaultProviderRegistryHost, - Namespace: "hashicorp", - Type: "null", - }, - }, - { - Addr: addrs.Resource{ - Mode: addrs.DataResourceMode, - Type: "terraform_remote_state", - Name: "baz", - }.InModule(addrs.RootModule), - Want: addrs.Provider{ - // As a special case, the type prefix "terraform_" maps to - // the builtin provider, not the default one. - Hostname: addrs.BuiltInProviderHost, - Namespace: addrs.BuiltInProviderNamespace, - Type: "terraform", - }, - }, - { - Addr: addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "null_resource", - Name: "baz", - }.InModule(addrs.RootModule), - Config: &configs.Resource{ - // Just enough configs.Resource for the Provider method. Not - // actually valid for general use. - Provider: addrs.Provider{ - Hostname: addrs.DefaultProviderRegistryHost, - Namespace: "awesomecorp", - Type: "happycloud", - }, - }, - // The config overrides the default behavior. - Want: addrs.Provider{ - Hostname: addrs.DefaultProviderRegistryHost, - Namespace: "awesomecorp", - Type: "happycloud", - }, - }, - { - Addr: addrs.Resource{ - Mode: addrs.DataResourceMode, - Type: "terraform_remote_state", - Name: "baz", - }.InModule(addrs.RootModule), - Config: &configs.Resource{ - // Just enough configs.Resource for the Provider method. Not - // actually valid for general use. - Provider: addrs.Provider{ - Hostname: addrs.DefaultProviderRegistryHost, - Namespace: "awesomecorp", - Type: "happycloud", - }, - }, - // The config overrides the default behavior. - Want: addrs.Provider{ - Hostname: addrs.DefaultProviderRegistryHost, - Namespace: "awesomecorp", - Type: "happycloud", - }, - }, - } - - for _, test := range tests { - var name string - if test.Config != nil { - name = fmt.Sprintf("%s with configured %s", test.Addr, test.Config.Provider) - } else { - name = fmt.Sprintf("%s with no configuration", test.Addr) - } - t.Run(name, func(t *testing.T) { - node := &NodeAbstractResource{ - // Just enough NodeAbstractResource for the Provider function. - // (This would not be valid for some other functions.) - Addr: test.Addr, - Config: test.Config, - } - got := node.Provider() - if got != test.Want { - t.Errorf("wrong result\naddr: %s\nconfig: %#v\ngot: %s\nwant: %s", test.Addr, test.Config, got, test.Want) - } - }) - } -} - -// Make sure ProvideBy returns the final resolved provider -func TestNodeAbstractResourceSetProvider(t *testing.T) { - node := &NodeAbstractResource{ - - // Just enough NodeAbstractResource for the Provider function. - // (This would not be valid for some other functions.) - Addr: addrs.Resource{ - Mode: addrs.DataResourceMode, - Type: "terraform_remote_state", - Name: "baz", - }.InModule(addrs.RootModule), - Config: &configs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "terraform_remote_state", - Name: "baz", - // Just enough configs.Resource for the Provider method. Not - // actually valid for general use. - Provider: addrs.Provider{ - Hostname: addrs.DefaultProviderRegistryHost, - Namespace: "awesomecorp", - Type: "happycloud", - }, - }, - } - - p, exact := node.ProvidedBy() - if exact { - t.Fatalf("no exact provider should be found from this confniguration, got %q\n", p) - } - - // the implied non-exact provider should be "terraform" - lpc, ok := p.(addrs.LocalProviderConfig) - if !ok { - t.Fatalf("expected LocalProviderConfig, got %#v\n", p) - } - - if lpc.LocalName != "terraform" { - t.Fatalf("expected non-exact provider of 'terraform', got %q", lpc.LocalName) - } - - // now set a resolved provider for the resource - resolved := addrs.AbsProviderConfig{ - Provider: addrs.Provider{ - Hostname: addrs.DefaultProviderRegistryHost, - Namespace: "awesomecorp", - Type: "happycloud", - }, - Module: addrs.RootModule, - Alias: "test", - } - - node.SetProvider(resolved) - p, exact = node.ProvidedBy() - if !exact { - t.Fatalf("exact provider should be found, got %q\n", p) - } - - apc, ok := p.(addrs.AbsProviderConfig) - if !ok { - t.Fatalf("expected AbsProviderConfig, got %#v\n", p) - } - - if apc.String() != resolved.String() { - t.Fatalf("incorrect resolved config: got %#v, wanted %#v\n", apc, resolved) - } -} - -func TestNodeAbstractResource_ReadResourceInstanceState(t *testing.T) { - mockProvider := mockProviderWithResourceTypeSchema("aws_instance", &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Optional: true, - }, - }, - }) - // This test does not configure the provider, but the mock provider will - // check that this was called and report errors. - mockProvider.ConfigureProviderCalled = true - - tests := map[string]struct { - State *states.State - Node *NodeAbstractResource - ExpectedInstanceId string - }{ - "ReadState gets primary instance state": { - State: states.BuildState(func(s *states.SyncState) { - providerAddr := addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("aws"), - Module: addrs.RootModule, - } - oneAddr := addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "bar", - }.Absolute(addrs.RootModuleInstance) - s.SetResourceProvider(oneAddr, providerAddr) - s.SetResourceInstanceCurrent(oneAddr.Instance(addrs.NoKey), &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"i-abc123"}`), - }, providerAddr) - }), - Node: &NodeAbstractResource{ - Addr: mustConfigResourceAddr("aws_instance.bar"), - ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - }, - ExpectedInstanceId: "i-abc123", - }, - } - - for k, test := range tests { - t.Run(k, func(t *testing.T) { - ctx := new(MockEvalContext) - ctx.StateState = test.State.SyncWrapper() - ctx.PathPath = addrs.RootModuleInstance - ctx.ProviderSchemaSchema = mockProvider.ProviderSchema() - - ctx.ProviderProvider = providers.Interface(mockProvider) - - got, readDiags := test.Node.readResourceInstanceState(ctx, test.Node.Addr.Resource.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)) - if readDiags.HasErrors() { - t.Fatalf("[%s] Got err: %#v", k, readDiags.Err()) - } - - expected := test.ExpectedInstanceId - - if !(got != nil && got.Value.GetAttr("id") == cty.StringVal(expected)) { - t.Fatalf("[%s] Expected output with ID %#v, got: %#v", k, expected, got) - } - }) - } -} - -func TestNodeAbstractResource_ReadResourceInstanceStateDeposed(t *testing.T) { - mockProvider := mockProviderWithResourceTypeSchema("aws_instance", &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Optional: true, - }, - }, - }) - // This test does not configure the provider, but the mock provider will - // check that this was called and report errors. - mockProvider.ConfigureProviderCalled = true - - tests := map[string]struct { - State *states.State - Node *NodeAbstractResource - ExpectedInstanceId string - }{ - "ReadStateDeposed gets deposed instance": { - State: states.BuildState(func(s *states.SyncState) { - providerAddr := addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("aws"), - Module: addrs.RootModule, - } - oneAddr := addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "bar", - }.Absolute(addrs.RootModuleInstance) - s.SetResourceProvider(oneAddr, providerAddr) - s.SetResourceInstanceDeposed(oneAddr.Instance(addrs.NoKey), states.DeposedKey("00000001"), &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"i-abc123"}`), - }, providerAddr) - }), - Node: &NodeAbstractResource{ - Addr: mustConfigResourceAddr("aws_instance.bar"), - ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - }, - ExpectedInstanceId: "i-abc123", - }, - } - for k, test := range tests { - t.Run(k, func(t *testing.T) { - ctx := new(MockEvalContext) - ctx.StateState = test.State.SyncWrapper() - ctx.PathPath = addrs.RootModuleInstance - ctx.ProviderSchemaSchema = mockProvider.ProviderSchema() - ctx.ProviderProvider = providers.Interface(mockProvider) - - key := states.DeposedKey("00000001") // shim from legacy state assigns 0th deposed index this key - - got, readDiags := test.Node.readResourceInstanceStateDeposed(ctx, test.Node.Addr.Resource.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), key) - if readDiags.HasErrors() { - t.Fatalf("[%s] Got err: %#v", k, readDiags.Err()) - } - - expected := test.ExpectedInstanceId - - if !(got != nil && got.Value.GetAttr("id") == cty.StringVal(expected)) { - t.Fatalf("[%s] Expected output with ID %#v, got: %#v", k, expected, got) - } - }) - } -} diff --git a/internal/terraform/node_resource_apply.go b/internal/terraform/node_resource_apply.go deleted file mode 100644 index 6f7b46af6e9a..000000000000 --- a/internal/terraform/node_resource_apply.go +++ /dev/null @@ -1,112 +0,0 @@ -package terraform - -import ( - "log" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/dag" - "github.com/hashicorp/terraform/internal/lang" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -// nodeExpandApplyableResource handles the first layer of resource -// expansion during apply. Even though the resource instances themselves are -// already expanded from the plan, we still need to expand the -// NodeApplyableResource nodes into their respective modules. -type nodeExpandApplyableResource struct { - *NodeAbstractResource -} - -var ( - _ GraphNodeDynamicExpandable = (*nodeExpandApplyableResource)(nil) - _ GraphNodeReferenceable = (*nodeExpandApplyableResource)(nil) - _ GraphNodeReferencer = (*nodeExpandApplyableResource)(nil) - _ GraphNodeConfigResource = (*nodeExpandApplyableResource)(nil) - _ GraphNodeAttachResourceConfig = (*nodeExpandApplyableResource)(nil) - _ graphNodeExpandsInstances = (*nodeExpandApplyableResource)(nil) - _ GraphNodeTargetable = (*nodeExpandApplyableResource)(nil) -) - -func (n *nodeExpandApplyableResource) expandsInstances() { -} - -func (n *nodeExpandApplyableResource) References() []*addrs.Reference { - return (&NodeApplyableResource{NodeAbstractResource: n.NodeAbstractResource}).References() -} - -func (n *nodeExpandApplyableResource) Name() string { - return n.NodeAbstractResource.Name() + " (expand)" -} - -func (n *nodeExpandApplyableResource) DynamicExpand(ctx EvalContext) (*Graph, error) { - var g Graph - - expander := ctx.InstanceExpander() - moduleInstances := expander.ExpandModule(n.Addr.Module) - for _, module := range moduleInstances { - g.Add(&NodeApplyableResource{ - NodeAbstractResource: n.NodeAbstractResource, - Addr: n.Addr.Resource.Absolute(module), - }) - } - addRootNodeToGraph(&g) - - return &g, nil -} - -// NodeApplyableResource represents a resource that is "applyable": -// it may need to have its record in the state adjusted to match configuration. -// -// Unlike in the plan walk, this resource node does not DynamicExpand. Instead, -// it should be inserted into the same graph as any instances of the nodes -// with dependency edges ensuring that the resource is evaluated before any -// of its instances, which will turn ensure that the whole-resource record -// in the state is suitably prepared to receive any updates to instances. -type NodeApplyableResource struct { - *NodeAbstractResource - - Addr addrs.AbsResource -} - -var ( - _ GraphNodeModuleInstance = (*NodeApplyableResource)(nil) - _ GraphNodeConfigResource = (*NodeApplyableResource)(nil) - _ GraphNodeExecutable = (*NodeApplyableResource)(nil) - _ GraphNodeProviderConsumer = (*NodeApplyableResource)(nil) - _ GraphNodeAttachResourceConfig = (*NodeApplyableResource)(nil) - _ GraphNodeReferencer = (*NodeApplyableResource)(nil) -) - -func (n *NodeApplyableResource) Path() addrs.ModuleInstance { - return n.Addr.Module -} - -func (n *NodeApplyableResource) References() []*addrs.Reference { - if n.Config == nil { - log.Printf("[WARN] NodeApplyableResource %q: no configuration, so can't determine References", dag.VertexName(n)) - return nil - } - - var result []*addrs.Reference - - // Since this node type only updates resource-level metadata, we only - // need to worry about the parts of the configuration that affect - // our "each mode": the count and for_each meta-arguments. - refs, _ := lang.ReferencesInExpr(n.Config.Count) - result = append(result, refs...) - refs, _ = lang.ReferencesInExpr(n.Config.ForEach) - result = append(result, refs...) - - return result -} - -// GraphNodeExecutable -func (n *NodeApplyableResource) Execute(ctx EvalContext, op walkOperation) tfdiags.Diagnostics { - if n.Config == nil { - // Nothing to do, then. - log.Printf("[TRACE] NodeApplyableResource: no configuration present for %s", n.Name()) - return nil - } - - return n.writeResourceState(ctx, n.Addr) -} diff --git a/internal/terraform/node_resource_apply_instance.go b/internal/terraform/node_resource_apply_instance.go deleted file mode 100644 index 82aebec296c4..000000000000 --- a/internal/terraform/node_resource_apply_instance.go +++ /dev/null @@ -1,486 +0,0 @@ -package terraform - -import ( - "fmt" - "log" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/instances" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/plans/objchange" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -// NodeApplyableResourceInstance represents a resource instance that is -// "applyable": it is ready to be applied and is represented by a diff. -// -// This node is for a specific instance of a resource. It will usually be -// accompanied in the graph by a NodeApplyableResource representing its -// containing resource, and should depend on that node to ensure that the -// state is properly prepared to receive changes to instances. -type NodeApplyableResourceInstance struct { - *NodeAbstractResourceInstance - - graphNodeDeposer // implementation of GraphNodeDeposerConfig - - // If this node is forced to be CreateBeforeDestroy, we need to record that - // in the state to. - ForceCreateBeforeDestroy bool - - // forceReplace are resource instance addresses where the user wants to - // force generating a replace action. This set isn't pre-filtered, so - // it might contain addresses that have nothing to do with the resource - // that this node represents, which the node itself must therefore ignore. - forceReplace []addrs.AbsResourceInstance -} - -var ( - _ GraphNodeConfigResource = (*NodeApplyableResourceInstance)(nil) - _ GraphNodeResourceInstance = (*NodeApplyableResourceInstance)(nil) - _ GraphNodeCreator = (*NodeApplyableResourceInstance)(nil) - _ GraphNodeReferencer = (*NodeApplyableResourceInstance)(nil) - _ GraphNodeDeposer = (*NodeApplyableResourceInstance)(nil) - _ GraphNodeExecutable = (*NodeApplyableResourceInstance)(nil) - _ GraphNodeAttachDependencies = (*NodeApplyableResourceInstance)(nil) -) - -// CreateBeforeDestroy returns this node's CreateBeforeDestroy status. -func (n *NodeApplyableResourceInstance) CreateBeforeDestroy() bool { - if n.ForceCreateBeforeDestroy { - return n.ForceCreateBeforeDestroy - } - - if n.Config != nil && n.Config.Managed != nil { - return n.Config.Managed.CreateBeforeDestroy - } - - return false -} - -func (n *NodeApplyableResourceInstance) ModifyCreateBeforeDestroy(v bool) error { - n.ForceCreateBeforeDestroy = v - return nil -} - -// GraphNodeCreator -func (n *NodeApplyableResourceInstance) CreateAddr() *addrs.AbsResourceInstance { - addr := n.ResourceInstanceAddr() - return &addr -} - -// GraphNodeReferencer, overriding NodeAbstractResourceInstance -func (n *NodeApplyableResourceInstance) References() []*addrs.Reference { - // Start with the usual resource instance implementation - ret := n.NodeAbstractResourceInstance.References() - - // Applying a resource must also depend on the destruction of any of its - // dependencies, since this may for example affect the outcome of - // evaluating an entire list of resources with "count" set (by reducing - // the count). - // - // However, we can't do this in create_before_destroy mode because that - // would create a dependency cycle. We make a compromise here of requiring - // changes to be updated across two applies in this case, since the first - // plan will use the old values. - if !n.CreateBeforeDestroy() { - for _, ref := range ret { - switch tr := ref.Subject.(type) { - case addrs.ResourceInstance: - newRef := *ref // shallow copy so we can mutate - newRef.Subject = tr.Phase(addrs.ResourceInstancePhaseDestroy) - newRef.Remaining = nil // can't access attributes of something being destroyed - ret = append(ret, &newRef) - case addrs.Resource: - newRef := *ref // shallow copy so we can mutate - newRef.Subject = tr.Phase(addrs.ResourceInstancePhaseDestroy) - newRef.Remaining = nil // can't access attributes of something being destroyed - ret = append(ret, &newRef) - } - } - } - - return ret -} - -// GraphNodeAttachDependencies -func (n *NodeApplyableResourceInstance) AttachDependencies(deps []addrs.ConfigResource) { - n.Dependencies = deps -} - -// GraphNodeExecutable -func (n *NodeApplyableResourceInstance) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) { - addr := n.ResourceInstanceAddr() - - if n.Config == nil { - // If there is no config, and there is no change, then we have nothing - // to do and the change was left in the plan for informational - // purposes only. - changes := ctx.Changes() - csrc := changes.GetResourceInstanceChange(n.ResourceInstanceAddr(), states.CurrentGen) - if csrc == nil || csrc.Action == plans.NoOp { - log.Printf("[DEBUG] NodeApplyableResourceInstance: No config or planned change recorded for %s", n.Addr) - return nil - } - - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Resource node has no configuration attached", - fmt.Sprintf( - "The graph node for %s has no configuration attached to it. This suggests a bug in Terraform's apply graph builder; please report it!", - addr, - ), - )) - return diags - } - - // Eval info is different depending on what kind of resource this is - switch n.Config.Mode { - case addrs.ManagedResourceMode: - return n.managedResourceExecute(ctx) - case addrs.DataResourceMode: - return n.dataResourceExecute(ctx) - default: - panic(fmt.Errorf("unsupported resource mode %s", n.Config.Mode)) - } -} - -func (n *NodeApplyableResourceInstance) dataResourceExecute(ctx EvalContext) (diags tfdiags.Diagnostics) { - _, providerSchema, err := getProvider(ctx, n.ResolvedProvider) - diags = diags.Append(err) - if diags.HasErrors() { - return diags - } - - change, err := n.readDiff(ctx, providerSchema) - diags = diags.Append(err) - if diags.HasErrors() { - return diags - } - // Stop early if we don't actually have a diff - if change == nil { - return diags - } - if change.Action != plans.Read && change.Action != plans.NoOp { - diags = diags.Append(fmt.Errorf("nonsensical planned action %#v for %s; this is a bug in Terraform", change.Action, n.Addr)) - } - - // In this particular call to applyDataSource we include our planned - // change, which signals that we expect this read to complete fully - // with no unknown values; it'll produce an error if not. - state, repeatData, applyDiags := n.applyDataSource(ctx, change) - diags = diags.Append(applyDiags) - if diags.HasErrors() { - return diags - } - - if state != nil { - // If n.applyDataSource returned a nil state object with no accompanying - // errors then it determined that the given change doesn't require - // actually reading the data (e.g. because it was already read during - // the plan phase) and so we're only running through here to get the - // extra details like precondition/postcondition checks. - diags = diags.Append(n.writeResourceInstanceState(ctx, state, workingState)) - if diags.HasErrors() { - return diags - } - } - - diags = diags.Append(n.writeChange(ctx, nil, "")) - - diags = diags.Append(updateStateHook(ctx)) - - // Post-conditions might block further progress. We intentionally do this - // _after_ writing the state/diff because we want to check against - // the result of the operation, and to fail on future operations - // until the user makes the condition succeed. - checkDiags := evalCheckRules( - addrs.ResourcePostcondition, - n.Config.Postconditions, - ctx, n.ResourceInstanceAddr(), - repeatData, - tfdiags.Error, - ) - diags = diags.Append(checkDiags) - - return diags -} - -func (n *NodeApplyableResourceInstance) managedResourceExecute(ctx EvalContext) (diags tfdiags.Diagnostics) { - // Declare a bunch of variables that are used for state during - // evaluation. Most of this are written to by-address below. - var state *states.ResourceInstanceObject - var createBeforeDestroyEnabled bool - var deposedKey states.DeposedKey - - addr := n.ResourceInstanceAddr().Resource - _, providerSchema, err := getProvider(ctx, n.ResolvedProvider) - diags = diags.Append(err) - if diags.HasErrors() { - return diags - } - - // Get the saved diff for apply - diffApply, err := n.readDiff(ctx, providerSchema) - diags = diags.Append(err) - if diags.HasErrors() { - return diags - } - - // We don't want to do any destroys - // (these are handled by NodeDestroyResourceInstance instead) - if diffApply == nil || diffApply.Action == plans.Delete { - return diags - } - if diffApply.Action == plans.Read { - diags = diags.Append(fmt.Errorf("nonsensical planned action %#v for %s; this is a bug in Terraform", diffApply.Action, n.Addr)) - } - - destroy := (diffApply.Action == plans.Delete || diffApply.Action.IsReplace()) - // Get the stored action for CBD if we have a plan already - createBeforeDestroyEnabled = diffApply.Change.Action == plans.CreateThenDelete - - if destroy && n.CreateBeforeDestroy() { - createBeforeDestroyEnabled = true - } - - if createBeforeDestroyEnabled { - state := ctx.State() - if n.PreallocatedDeposedKey == states.NotDeposed { - deposedKey = state.DeposeResourceInstanceObject(n.Addr) - } else { - deposedKey = n.PreallocatedDeposedKey - state.DeposeResourceInstanceObjectForceKey(n.Addr, deposedKey) - } - log.Printf("[TRACE] managedResourceExecute: prior object for %s now deposed with key %s", n.Addr, deposedKey) - } - - state, readDiags := n.readResourceInstanceState(ctx, n.ResourceInstanceAddr()) - diags = diags.Append(readDiags) - if diags.HasErrors() { - return diags - } - - // Get the saved diff - diff, err := n.readDiff(ctx, providerSchema) - diags = diags.Append(err) - if diags.HasErrors() { - return diags - } - - // Make a new diff, in case we've learned new values in the state - // during apply which we can now incorporate. - diffApply, _, repeatData, planDiags := n.plan(ctx, diff, state, false, n.forceReplace) - diags = diags.Append(planDiags) - if diags.HasErrors() { - return diags - } - - // Compare the diffs - diags = diags.Append(n.checkPlannedChange(ctx, diff, diffApply, providerSchema)) - if diags.HasErrors() { - return diags - } - - diffApply = reducePlan(addr, diffApply, false) - // reducePlan may have simplified our planned change - // into a NoOp if it only requires destroying, since destroying - // is handled by NodeDestroyResourceInstance. If so, we'll - // still run through most of the logic here because we do still - // need to deal with other book-keeping such as marking the - // change as "complete", and running the author's postconditions. - - diags = diags.Append(n.preApplyHook(ctx, diffApply)) - if diags.HasErrors() { - return diags - } - - // If there is no change, there was nothing to apply, and we don't need to - // re-write the state, but we do need to re-evaluate postconditions. - if diffApply.Action == plans.NoOp { - return diags.Append(n.managedResourcePostconditions(ctx, repeatData)) - } - - state, applyDiags := n.apply(ctx, state, diffApply, n.Config, repeatData, n.CreateBeforeDestroy()) - diags = diags.Append(applyDiags) - - // We clear the change out here so that future nodes don't see a change - // that is already complete. - err = n.writeChange(ctx, nil, "") - if err != nil { - return diags.Append(err) - } - - state = maybeTainted(addr.Absolute(ctx.Path()), state, diffApply, diags.Err()) - - if state != nil { - // dependencies are always updated to match the configuration during apply - state.Dependencies = n.Dependencies - } - err = n.writeResourceInstanceState(ctx, state, workingState) - if err != nil { - return diags.Append(err) - } - - // Run Provisioners - createNew := (diffApply.Action == plans.Create || diffApply.Action.IsReplace()) - applyProvisionersDiags := n.evalApplyProvisioners(ctx, state, createNew, configs.ProvisionerWhenCreate) - // the provisioner errors count as port of the apply error, so we can bundle the diags - diags = diags.Append(applyProvisionersDiags) - - state = maybeTainted(addr.Absolute(ctx.Path()), state, diffApply, diags.Err()) - - err = n.writeResourceInstanceState(ctx, state, workingState) - if err != nil { - return diags.Append(err) - } - - if createBeforeDestroyEnabled && diags.HasErrors() { - if deposedKey == states.NotDeposed { - // This should never happen, and so it always indicates a bug. - // We should evaluate this node only if we've previously deposed - // an object as part of the same operation. - if diffApply != nil { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Attempt to restore non-existent deposed object", - fmt.Sprintf( - "Terraform has encountered a bug where it would need to restore a deposed object for %s without knowing a deposed object key for that object. This occurred during a %s action. This is a bug in Terraform; please report it!", - addr, diffApply.Action, - ), - )) - } else { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Attempt to restore non-existent deposed object", - fmt.Sprintf( - "Terraform has encountered a bug where it would need to restore a deposed object for %s without knowing a deposed object key for that object. This is a bug in Terraform; please report it!", - addr, - ), - )) - } - } else { - restored := ctx.State().MaybeRestoreResourceInstanceDeposed(addr.Absolute(ctx.Path()), deposedKey) - if restored { - log.Printf("[TRACE] managedResourceExecute: %s deposed object %s was restored as the current object", addr, deposedKey) - } else { - log.Printf("[TRACE] managedResourceExecute: %s deposed object %s remains deposed", addr, deposedKey) - } - } - } - - diags = diags.Append(n.postApplyHook(ctx, state, diags.Err())) - diags = diags.Append(updateStateHook(ctx)) - - // Post-conditions might block further progress. We intentionally do this - // _after_ writing the state because we want to check against - // the result of the operation, and to fail on future operations - // until the user makes the condition succeed. - return diags.Append(n.managedResourcePostconditions(ctx, repeatData)) -} - -func (n *NodeApplyableResourceInstance) managedResourcePostconditions(ctx EvalContext, repeatData instances.RepetitionData) (diags tfdiags.Diagnostics) { - - checkDiags := evalCheckRules( - addrs.ResourcePostcondition, - n.Config.Postconditions, - ctx, n.ResourceInstanceAddr(), repeatData, - tfdiags.Error, - ) - return diags.Append(checkDiags) -} - -// checkPlannedChange produces errors if the _actual_ expected value is not -// compatible with what was recorded in the plan. -// -// Errors here are most often indicative of a bug in the provider, so our error -// messages will report with that in mind. It's also possible that there's a bug -// in Terraform's Core's own "proposed new value" code in EvalDiff. -func (n *NodeApplyableResourceInstance) checkPlannedChange(ctx EvalContext, plannedChange, actualChange *plans.ResourceInstanceChange, providerSchema *ProviderSchema) tfdiags.Diagnostics { - var diags tfdiags.Diagnostics - addr := n.ResourceInstanceAddr().Resource - - schema, _ := providerSchema.SchemaForResourceAddr(addr.ContainingResource()) - if schema == nil { - // Should be caught during validation, so we don't bother with a pretty error here - diags = diags.Append(fmt.Errorf("provider does not support %q", addr.Resource.Type)) - return diags - } - - absAddr := addr.Absolute(ctx.Path()) - - log.Printf("[TRACE] checkPlannedChange: Verifying that actual change (action %s) matches planned change (action %s)", actualChange.Action, plannedChange.Action) - - if plannedChange.Action != actualChange.Action { - switch { - case plannedChange.Action == plans.Update && actualChange.Action == plans.NoOp: - // It's okay for an update to become a NoOp once we've filled in - // all of the unknown values, since the final values might actually - // match what was there before after all. - log.Printf("[DEBUG] After incorporating new values learned so far during apply, %s change has become NoOp", absAddr) - - case (plannedChange.Action == plans.CreateThenDelete && actualChange.Action == plans.DeleteThenCreate) || - (plannedChange.Action == plans.DeleteThenCreate && actualChange.Action == plans.CreateThenDelete): - // If the order of replacement changed, then that is a bug in terraform - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Terraform produced inconsistent final plan", - fmt.Sprintf( - "When expanding the plan for %s to include new values learned so far during apply, the planned action changed from %s to %s.\n\nThis is a bug in Terraform and should be reported.", - absAddr, plannedChange.Action, actualChange.Action, - ), - )) - default: - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Provider produced inconsistent final plan", - fmt.Sprintf( - "When expanding the plan for %s to include new values learned so far during apply, provider %q changed the planned action from %s to %s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.", - absAddr, n.ResolvedProvider.Provider.String(), - plannedChange.Action, actualChange.Action, - ), - )) - } - } - - errs := objchange.AssertObjectCompatible(schema, plannedChange.After, actualChange.After) - for _, err := range errs { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Provider produced inconsistent final plan", - fmt.Sprintf( - "When expanding the plan for %s to include new values learned so far during apply, provider %q produced an invalid new value for %s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.", - absAddr, n.ResolvedProvider.Provider.String(), tfdiags.FormatError(err), - ), - )) - } - return diags -} - -// maybeTainted takes the resource addr, new value, planned change, and possible -// error from an apply operation and return a new instance object marked as -// tainted if it appears that a create operation has failed. -func maybeTainted(addr addrs.AbsResourceInstance, state *states.ResourceInstanceObject, change *plans.ResourceInstanceChange, err error) *states.ResourceInstanceObject { - if state == nil || change == nil || err == nil { - return state - } - if state.Status == states.ObjectTainted { - log.Printf("[TRACE] maybeTainted: %s was already tainted, so nothing to do", addr) - return state - } - if change.Action == plans.Create { - // If there are errors during a _create_ then the object is - // in an undefined state, and so we'll mark it as tainted so - // we can try again on the next run. - // - // We don't do this for other change actions because errors - // during updates will often not change the remote object at all. - // If there _were_ changes prior to the error, it's the provider's - // responsibility to record the effect of those changes in the - // object value it returned. - log.Printf("[TRACE] maybeTainted: %s encountered an error during creation, so it is now marked as tainted", addr) - return state.AsTainted() - } - return state -} diff --git a/internal/terraform/node_resource_apply_test.go b/internal/terraform/node_resource_apply_test.go deleted file mode 100644 index 4fd994954418..000000000000 --- a/internal/terraform/node_resource_apply_test.go +++ /dev/null @@ -1,63 +0,0 @@ -package terraform - -import ( - "testing" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/instances" - "github.com/hashicorp/terraform/internal/states" -) - -func TestNodeApplyableResourceExecute(t *testing.T) { - state := states.NewState() - ctx := &MockEvalContext{ - StateState: state.SyncWrapper(), - InstanceExpanderExpander: instances.NewExpander(), - } - - t.Run("no config", func(t *testing.T) { - node := NodeApplyableResource{ - NodeAbstractResource: &NodeAbstractResource{ - Config: nil, - }, - Addr: mustAbsResourceAddr("test_instance.foo"), - } - diags := node.Execute(ctx, walkApply) - if diags.HasErrors() { - t.Fatalf("unexpected error: %s", diags.Err()) - } - if !state.Empty() { - t.Fatalf("expected no state, got:\n %s", state.String()) - } - }) - - t.Run("simple", func(t *testing.T) { - - node := NodeApplyableResource{ - NodeAbstractResource: &NodeAbstractResource{ - Config: &configs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_instance", - Name: "foo", - }, - ResolvedProvider: addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("test"), - Module: addrs.RootModule, - }, - }, - Addr: mustAbsResourceAddr("test_instance.foo"), - } - diags := node.Execute(ctx, walkApply) - if diags.HasErrors() { - t.Fatalf("unexpected error: %s", diags.Err()) - } - if state.Empty() { - t.Fatal("expected resources in state, got empty state") - } - r := state.Resource(mustAbsResourceAddr("test_instance.foo")) - if r == nil { - t.Fatal("test_instance.foo not found in state") - } - }) -} diff --git a/internal/terraform/node_resource_destroy.go b/internal/terraform/node_resource_destroy.go deleted file mode 100644 index a468ad020ba1..000000000000 --- a/internal/terraform/node_resource_destroy.go +++ /dev/null @@ -1,234 +0,0 @@ -package terraform - -import ( - "fmt" - "log" - - "github.com/hashicorp/terraform/internal/instances" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/tfdiags" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/states" -) - -// NodeDestroyResourceInstance represents a resource instance that is to be -// destroyed. -type NodeDestroyResourceInstance struct { - *NodeAbstractResourceInstance - - // If DeposedKey is set to anything other than states.NotDeposed then - // this node destroys a deposed object of the associated instance - // rather than its current object. - DeposedKey states.DeposedKey -} - -var ( - _ GraphNodeModuleInstance = (*NodeDestroyResourceInstance)(nil) - _ GraphNodeConfigResource = (*NodeDestroyResourceInstance)(nil) - _ GraphNodeResourceInstance = (*NodeDestroyResourceInstance)(nil) - _ GraphNodeDestroyer = (*NodeDestroyResourceInstance)(nil) - _ GraphNodeDestroyerCBD = (*NodeDestroyResourceInstance)(nil) - _ GraphNodeReferenceable = (*NodeDestroyResourceInstance)(nil) - _ GraphNodeReferencer = (*NodeDestroyResourceInstance)(nil) - _ GraphNodeExecutable = (*NodeDestroyResourceInstance)(nil) - _ GraphNodeProviderConsumer = (*NodeDestroyResourceInstance)(nil) - _ GraphNodeProvisionerConsumer = (*NodeDestroyResourceInstance)(nil) -) - -func (n *NodeDestroyResourceInstance) Name() string { - if n.DeposedKey != states.NotDeposed { - return fmt.Sprintf("%s (destroy deposed %s)", n.ResourceInstanceAddr(), n.DeposedKey) - } - return n.ResourceInstanceAddr().String() + " (destroy)" -} - -func (n *NodeDestroyResourceInstance) ProvidedBy() (addr addrs.ProviderConfig, exact bool) { - if n.Addr.Resource.Resource.Mode == addrs.DataResourceMode { - // indicate that this node does not require a configured provider - return nil, true - } - return n.NodeAbstractResourceInstance.ProvidedBy() -} - -// GraphNodeDestroyer -func (n *NodeDestroyResourceInstance) DestroyAddr() *addrs.AbsResourceInstance { - addr := n.ResourceInstanceAddr() - return &addr -} - -// GraphNodeDestroyerCBD -func (n *NodeDestroyResourceInstance) CreateBeforeDestroy() bool { - // State takes precedence during destroy. - // If the resource was removed, there is no config to check. - // If CBD was forced from descendent, it should be saved in the state - // already. - if s := n.instanceState; s != nil { - if s.Current != nil { - return s.Current.CreateBeforeDestroy - } - } - - if n.Config != nil && n.Config.Managed != nil { - return n.Config.Managed.CreateBeforeDestroy - } - - return false -} - -// GraphNodeDestroyerCBD -func (n *NodeDestroyResourceInstance) ModifyCreateBeforeDestroy(v bool) error { - return nil -} - -// GraphNodeReferenceable, overriding NodeAbstractResource -func (n *NodeDestroyResourceInstance) ReferenceableAddrs() []addrs.Referenceable { - normalAddrs := n.NodeAbstractResourceInstance.ReferenceableAddrs() - destroyAddrs := make([]addrs.Referenceable, len(normalAddrs)) - - phaseType := addrs.ResourceInstancePhaseDestroy - if n.CreateBeforeDestroy() { - phaseType = addrs.ResourceInstancePhaseDestroyCBD - } - - for i, normalAddr := range normalAddrs { - switch ta := normalAddr.(type) { - case addrs.Resource: - destroyAddrs[i] = ta.Phase(phaseType) - case addrs.ResourceInstance: - destroyAddrs[i] = ta.Phase(phaseType) - default: - destroyAddrs[i] = normalAddr - } - } - - return destroyAddrs -} - -// GraphNodeReferencer, overriding NodeAbstractResource -func (n *NodeDestroyResourceInstance) References() []*addrs.Reference { - // If we have a config, then we need to include destroy-time dependencies - if c := n.Config; c != nil && c.Managed != nil { - var result []*addrs.Reference - - // We include conn info and config for destroy time provisioners - // as dependencies that we have. - for _, p := range c.Managed.Provisioners { - schema := n.ProvisionerSchemas[p.Type] - - if p.When == configs.ProvisionerWhenDestroy { - if p.Connection != nil { - result = append(result, ReferencesFromConfig(p.Connection.Config, connectionBlockSupersetSchema)...) - } - result = append(result, ReferencesFromConfig(p.Config, schema)...) - } - } - - return result - } - - return nil -} - -// GraphNodeExecutable -func (n *NodeDestroyResourceInstance) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) { - addr := n.ResourceInstanceAddr() - - // Eval info is different depending on what kind of resource this is - switch addr.Resource.Resource.Mode { - case addrs.ManagedResourceMode: - return n.managedResourceExecute(ctx) - case addrs.DataResourceMode: - return n.dataResourceExecute(ctx) - default: - panic(fmt.Errorf("unsupported resource mode %s", n.Config.Mode)) - } -} - -func (n *NodeDestroyResourceInstance) managedResourceExecute(ctx EvalContext) (diags tfdiags.Diagnostics) { - addr := n.ResourceInstanceAddr() - - // Get our state - is := n.instanceState - if is == nil { - log.Printf("[WARN] NodeDestroyResourceInstance for %s with no state", addr) - } - - // These vars are updated through pointers at various stages below. - var changeApply *plans.ResourceInstanceChange - var state *states.ResourceInstanceObject - - _, providerSchema, err := getProvider(ctx, n.ResolvedProvider) - diags = diags.Append(err) - if diags.HasErrors() { - return diags - } - - changeApply, err = n.readDiff(ctx, providerSchema) - diags = diags.Append(err) - if changeApply == nil || diags.HasErrors() { - return diags - } - - changeApply = reducePlan(addr.Resource, changeApply, true) - // reducePlan may have simplified our planned change - // into a NoOp if it does not require destroying. - if changeApply == nil || changeApply.Action == plans.NoOp { - return diags - } - - state, readDiags := n.readResourceInstanceState(ctx, addr) - diags = diags.Append(readDiags) - if diags.HasErrors() { - return diags - } - - // Exit early if the state object is null after reading the state - if state == nil || state.Value.IsNull() { - return diags - } - - diags = diags.Append(n.preApplyHook(ctx, changeApply)) - if diags.HasErrors() { - return diags - } - - // Run destroy provisioners if not tainted - if state.Status != states.ObjectTainted { - applyProvisionersDiags := n.evalApplyProvisioners(ctx, state, false, configs.ProvisionerWhenDestroy) - diags = diags.Append(applyProvisionersDiags) - // keep the diags separate from the main set until we handle the cleanup - - if diags.HasErrors() { - // If we have a provisioning error, then we just call - // the post-apply hook now. - diags = diags.Append(n.postApplyHook(ctx, state, diags.Err())) - return diags - } - } - - // Managed resources need to be destroyed, while data sources - // are only removed from state. - // we pass a nil configuration to apply because we are destroying - s, d := n.apply(ctx, state, changeApply, nil, instances.RepetitionData{}, false) - state, diags = s, diags.Append(d) - // we don't return immediately here on error, so that the state can be - // finalized - - err = n.writeResourceInstanceState(ctx, state, workingState) - if err != nil { - return diags.Append(err) - } - - // create the err value for postApplyHook - diags = diags.Append(n.postApplyHook(ctx, state, diags.Err())) - diags = diags.Append(updateStateHook(ctx)) - return diags -} - -func (n *NodeDestroyResourceInstance) dataResourceExecute(ctx EvalContext) (diags tfdiags.Diagnostics) { - log.Printf("[TRACE] NodeDestroyResourceInstance: removing state object for %s", n.Addr) - ctx.State().SetResourceInstanceCurrent(n.Addr, nil, n.ResolvedProvider) - return diags.Append(updateStateHook(ctx)) -} diff --git a/internal/terraform/node_resource_destroy_deposed.go b/internal/terraform/node_resource_destroy_deposed.go deleted file mode 100644 index 702e0596c124..000000000000 --- a/internal/terraform/node_resource_destroy_deposed.go +++ /dev/null @@ -1,334 +0,0 @@ -package terraform - -import ( - "fmt" - "log" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/dag" - "github.com/hashicorp/terraform/internal/instances" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -// ConcreteResourceInstanceDeposedNodeFunc is a callback type used to convert -// an abstract resource instance to a concrete one of some type that has -// an associated deposed object key. -type ConcreteResourceInstanceDeposedNodeFunc func(*NodeAbstractResourceInstance, states.DeposedKey) dag.Vertex - -type GraphNodeDeposedResourceInstanceObject interface { - DeposedInstanceObjectKey() states.DeposedKey -} - -// NodePlanDeposedResourceInstanceObject represents deposed resource -// instance objects during plan. These are distinct from the primary object -// for each resource instance since the only valid operation to do with them -// is to destroy them. -// -// This node type is also used during the refresh walk to ensure that the -// record of a deposed object is up-to-date before we plan to destroy it. -type NodePlanDeposedResourceInstanceObject struct { - *NodeAbstractResourceInstance - DeposedKey states.DeposedKey - - // skipRefresh indicates that we should skip refreshing individual instances - skipRefresh bool - - // skipPlanChanges indicates we should skip trying to plan change actions - // for any instances. - skipPlanChanges bool -} - -var ( - _ GraphNodeDeposedResourceInstanceObject = (*NodePlanDeposedResourceInstanceObject)(nil) - _ GraphNodeConfigResource = (*NodePlanDeposedResourceInstanceObject)(nil) - _ GraphNodeResourceInstance = (*NodePlanDeposedResourceInstanceObject)(nil) - _ GraphNodeReferenceable = (*NodePlanDeposedResourceInstanceObject)(nil) - _ GraphNodeReferencer = (*NodePlanDeposedResourceInstanceObject)(nil) - _ GraphNodeExecutable = (*NodePlanDeposedResourceInstanceObject)(nil) - _ GraphNodeProviderConsumer = (*NodePlanDeposedResourceInstanceObject)(nil) - _ GraphNodeProvisionerConsumer = (*NodePlanDeposedResourceInstanceObject)(nil) -) - -func (n *NodePlanDeposedResourceInstanceObject) Name() string { - return fmt.Sprintf("%s (deposed %s)", n.ResourceInstanceAddr().String(), n.DeposedKey) -} - -func (n *NodePlanDeposedResourceInstanceObject) DeposedInstanceObjectKey() states.DeposedKey { - return n.DeposedKey -} - -// GraphNodeReferenceable implementation, overriding the one from NodeAbstractResourceInstance -func (n *NodePlanDeposedResourceInstanceObject) ReferenceableAddrs() []addrs.Referenceable { - // Deposed objects don't participate in references. - return nil -} - -// GraphNodeReferencer implementation, overriding the one from NodeAbstractResourceInstance -func (n *NodePlanDeposedResourceInstanceObject) References() []*addrs.Reference { - // We don't evaluate configuration for deposed objects, so they effectively - // make no references. - return nil -} - -// GraphNodeEvalable impl. -func (n *NodePlanDeposedResourceInstanceObject) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) { - log.Printf("[TRACE] NodePlanDeposedResourceInstanceObject: planning %s deposed object %s", n.Addr, n.DeposedKey) - - // Read the state for the deposed resource instance - state, err := n.readResourceInstanceStateDeposed(ctx, n.Addr, n.DeposedKey) - diags = diags.Append(err) - if diags.HasErrors() { - return diags - } - - // Note any upgrades that readResourceInstanceState might've done in the - // prevRunState, so that it'll conform to current schema. - diags = diags.Append(n.writeResourceInstanceStateDeposed(ctx, n.DeposedKey, state, prevRunState)) - if diags.HasErrors() { - return diags - } - // Also the refreshState, because that should still reflect schema upgrades - // even if not refreshing. - diags = diags.Append(n.writeResourceInstanceStateDeposed(ctx, n.DeposedKey, state, refreshState)) - if diags.HasErrors() { - return diags - } - - // We don't refresh during the planDestroy walk, since that is only adding - // the destroy changes to the plan and the provider will not be configured - // at this point. The other nodes use separate types for plan and destroy, - // while deposed instances are always a destroy operation, so the logic - // here is a bit overloaded. - if !n.skipRefresh && op != walkPlanDestroy { - // Refresh this object even though it is going to be destroyed, in - // case it's already been deleted outside of Terraform. If this is a - // normal plan, providers expect a Read request to remove missing - // resources from the plan before apply, and may not handle a missing - // resource during Delete correctly. If this is a simple refresh, - // Terraform is expected to remove the missing resource from the state - // entirely - refreshedState, refreshDiags := n.refresh(ctx, n.DeposedKey, state) - diags = diags.Append(refreshDiags) - if diags.HasErrors() { - return diags - } - - diags = diags.Append(n.writeResourceInstanceStateDeposed(ctx, n.DeposedKey, refreshedState, refreshState)) - if diags.HasErrors() { - return diags - } - - // If we refreshed then our subsequent planning should be in terms of - // the new object, not the original object. - state = refreshedState - } - - if !n.skipPlanChanges { - var change *plans.ResourceInstanceChange - change, destroyPlanDiags := n.planDestroy(ctx, state, n.DeposedKey) - diags = diags.Append(destroyPlanDiags) - if diags.HasErrors() { - return diags - } - - // NOTE: We don't check prevent_destroy for deposed objects, even - // though we would do so here for a "current" object, because - // if we've reached a point where an object is already deposed then - // we've already planned and partially-executed a create_before_destroy - // replace and we would've checked prevent_destroy at that point. We're - // now just need to get the deposed object destroyed, because there - // should be a new object already serving as its replacement. - - diags = diags.Append(n.writeChange(ctx, change, n.DeposedKey)) - if diags.HasErrors() { - return diags - } - - diags = diags.Append(n.writeResourceInstanceStateDeposed(ctx, n.DeposedKey, nil, workingState)) - } else { - // The working state should at least be updated with the result - // of upgrading and refreshing from above. - diags = diags.Append(n.writeResourceInstanceStateDeposed(ctx, n.DeposedKey, state, workingState)) - } - - return diags -} - -// NodeDestroyDeposedResourceInstanceObject represents deposed resource -// instance objects during apply. Nodes of this type are inserted by -// DiffTransformer when the planned changeset contains "delete" changes for -// deposed instance objects, and its only supported operation is to destroy -// and then forget the associated object. -type NodeDestroyDeposedResourceInstanceObject struct { - *NodeAbstractResourceInstance - DeposedKey states.DeposedKey -} - -var ( - _ GraphNodeDeposedResourceInstanceObject = (*NodeDestroyDeposedResourceInstanceObject)(nil) - _ GraphNodeConfigResource = (*NodeDestroyDeposedResourceInstanceObject)(nil) - _ GraphNodeResourceInstance = (*NodeDestroyDeposedResourceInstanceObject)(nil) - _ GraphNodeDestroyer = (*NodeDestroyDeposedResourceInstanceObject)(nil) - _ GraphNodeDestroyerCBD = (*NodeDestroyDeposedResourceInstanceObject)(nil) - _ GraphNodeReferenceable = (*NodeDestroyDeposedResourceInstanceObject)(nil) - _ GraphNodeReferencer = (*NodeDestroyDeposedResourceInstanceObject)(nil) - _ GraphNodeExecutable = (*NodeDestroyDeposedResourceInstanceObject)(nil) - _ GraphNodeProviderConsumer = (*NodeDestroyDeposedResourceInstanceObject)(nil) - _ GraphNodeProvisionerConsumer = (*NodeDestroyDeposedResourceInstanceObject)(nil) -) - -func (n *NodeDestroyDeposedResourceInstanceObject) Name() string { - return fmt.Sprintf("%s (destroy deposed %s)", n.ResourceInstanceAddr(), n.DeposedKey) -} - -func (n *NodeDestroyDeposedResourceInstanceObject) DeposedInstanceObjectKey() states.DeposedKey { - return n.DeposedKey -} - -// GraphNodeReferenceable implementation, overriding the one from NodeAbstractResourceInstance -func (n *NodeDestroyDeposedResourceInstanceObject) ReferenceableAddrs() []addrs.Referenceable { - // Deposed objects don't participate in references. - return nil -} - -// GraphNodeReferencer implementation, overriding the one from NodeAbstractResourceInstance -func (n *NodeDestroyDeposedResourceInstanceObject) References() []*addrs.Reference { - // We don't evaluate configuration for deposed objects, so they effectively - // make no references. - return nil -} - -// GraphNodeDestroyer -func (n *NodeDestroyDeposedResourceInstanceObject) DestroyAddr() *addrs.AbsResourceInstance { - addr := n.ResourceInstanceAddr() - return &addr -} - -// GraphNodeDestroyerCBD -func (n *NodeDestroyDeposedResourceInstanceObject) CreateBeforeDestroy() bool { - // A deposed instance is always CreateBeforeDestroy by definition, since - // we use deposed only to handle create-before-destroy. - return true -} - -// GraphNodeDestroyerCBD -func (n *NodeDestroyDeposedResourceInstanceObject) ModifyCreateBeforeDestroy(v bool) error { - if !v { - // Should never happen: deposed instances are _always_ create_before_destroy. - return fmt.Errorf("can't deactivate create_before_destroy for a deposed instance") - } - return nil -} - -// GraphNodeExecutable impl. -func (n *NodeDestroyDeposedResourceInstanceObject) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) { - var change *plans.ResourceInstanceChange - - // Read the state for the deposed resource instance - state, err := n.readResourceInstanceStateDeposed(ctx, n.Addr, n.DeposedKey) - if err != nil { - return diags.Append(err) - } - - if state == nil { - diags = diags.Append(fmt.Errorf("missing deposed state for %s (%s)", n.Addr, n.DeposedKey)) - return diags - } - - change, destroyPlanDiags := n.planDestroy(ctx, state, n.DeposedKey) - diags = diags.Append(destroyPlanDiags) - if diags.HasErrors() { - return diags - } - - // Call pre-apply hook - diags = diags.Append(n.preApplyHook(ctx, change)) - if diags.HasErrors() { - return diags - } - - // we pass a nil configuration to apply because we are destroying - state, applyDiags := n.apply(ctx, state, change, nil, instances.RepetitionData{}, false) - diags = diags.Append(applyDiags) - // don't return immediately on errors, we need to handle the state - - // Always write the resource back to the state deposed. If it - // was successfully destroyed it will be pruned. If it was not, it will - // be caught on the next run. - writeDiags := n.writeResourceInstanceState(ctx, state) - diags.Append(writeDiags) - if diags.HasErrors() { - return diags - } - - diags = diags.Append(n.postApplyHook(ctx, state, diags.Err())) - - return diags.Append(updateStateHook(ctx)) -} - -// GraphNodeDeposer is an optional interface implemented by graph nodes that -// might create a single new deposed object for a specific associated resource -// instance, allowing a caller to optionally pre-allocate a DeposedKey for -// it. -type GraphNodeDeposer interface { - // SetPreallocatedDeposedKey will be called during graph construction - // if a particular node must use a pre-allocated deposed key if/when it - // "deposes" the current object of its associated resource instance. - SetPreallocatedDeposedKey(key states.DeposedKey) -} - -// graphNodeDeposer is an embeddable implementation of GraphNodeDeposer. -// Embed it in a node type to get automatic support for it, and then access -// the field PreallocatedDeposedKey to access any pre-allocated key. -type graphNodeDeposer struct { - PreallocatedDeposedKey states.DeposedKey -} - -func (n *graphNodeDeposer) SetPreallocatedDeposedKey(key states.DeposedKey) { - n.PreallocatedDeposedKey = key -} - -func (n *NodeDestroyDeposedResourceInstanceObject) writeResourceInstanceState(ctx EvalContext, obj *states.ResourceInstanceObject) error { - absAddr := n.Addr - key := n.DeposedKey - state := ctx.State() - - if key == states.NotDeposed { - // should never happen - return fmt.Errorf("can't save deposed object for %s without a deposed key; this is a bug in Terraform that should be reported", absAddr) - } - - if obj == nil { - // No need to encode anything: we'll just write it directly. - state.SetResourceInstanceDeposed(absAddr, key, nil, n.ResolvedProvider) - log.Printf("[TRACE] writeResourceInstanceStateDeposed: removing state object for %s deposed %s", absAddr, key) - return nil - } - - _, providerSchema, err := getProvider(ctx, n.ResolvedProvider) - if err != nil { - return err - } - if providerSchema == nil { - // Should never happen, unless our state object is nil - panic("writeResourceInstanceStateDeposed used with no ProviderSchema object") - } - - schema, currentVersion := providerSchema.SchemaForResourceAddr(absAddr.ContainingResource().Resource) - if schema == nil { - // It shouldn't be possible to get this far in any real scenario - // without a schema, but we might end up here in contrived tests that - // fail to set up their world properly. - return fmt.Errorf("failed to encode %s in state: no resource type schema available", absAddr) - } - src, err := obj.Encode(schema.ImpliedType(), currentVersion) - if err != nil { - return fmt.Errorf("failed to encode %s in state: %s", absAddr, err) - } - - log.Printf("[TRACE] writeResourceInstanceStateDeposed: writing state object for %s deposed %s", absAddr, key) - state.SetResourceInstanceDeposed(absAddr, key, src, n.ResolvedProvider) - return nil -} diff --git a/internal/terraform/node_resource_destroy_deposed_test.go b/internal/terraform/node_resource_destroy_deposed_test.go deleted file mode 100644 index f173002a28df..000000000000 --- a/internal/terraform/node_resource_destroy_deposed_test.go +++ /dev/null @@ -1,212 +0,0 @@ -package terraform - -import ( - "testing" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" - "github.com/zclconf/go-cty/cty" -) - -func TestNodePlanDeposedResourceInstanceObject_Execute(t *testing.T) { - deposedKey := states.NewDeposedKey() - state := states.NewState() - absResource := mustResourceInstanceAddr("test_instance.foo") - state.Module(addrs.RootModuleInstance).SetResourceInstanceDeposed( - absResource.Resource, - deposedKey, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectTainted, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - p := testProvider("test") - p.ConfigureProvider(providers.ConfigureProviderRequest{}) - p.UpgradeResourceStateResponse = &providers.UpgradeResourceStateResponse{ - UpgradedState: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("bar"), - }), - } - ctx := &MockEvalContext{ - StateState: state.SyncWrapper(), - PrevRunStateState: state.DeepCopy().SyncWrapper(), - RefreshStateState: state.DeepCopy().SyncWrapper(), - ProviderProvider: p, - ProviderSchemaSchema: &ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test_instance": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - }, - }, - }, - }, - ChangesChanges: plans.NewChanges().SyncWrapper(), - } - - node := NodePlanDeposedResourceInstanceObject{ - NodeAbstractResourceInstance: &NodeAbstractResourceInstance{ - Addr: absResource, - NodeAbstractResource: NodeAbstractResource{ - ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - }, - }, - DeposedKey: deposedKey, - } - err := node.Execute(ctx, walkPlan) - if err != nil { - t.Fatalf("unexpected error: %s", err) - } - - if !p.UpgradeResourceStateCalled { - t.Errorf("UpgradeResourceState wasn't called; should've been called to upgrade the previous run's object") - } - if !p.ReadResourceCalled { - t.Errorf("ReadResource wasn't called; should've been called to refresh the deposed object") - } - - change := ctx.Changes().GetResourceInstanceChange(absResource, deposedKey) - if got, want := change.ChangeSrc.Action, plans.Delete; got != want { - t.Fatalf("wrong planned action\ngot: %s\nwant: %s", got, want) - } -} - -func TestNodeDestroyDeposedResourceInstanceObject_Execute(t *testing.T) { - deposedKey := states.NewDeposedKey() - state := states.NewState() - absResource := mustResourceInstanceAddr("test_instance.foo") - state.Module(addrs.RootModuleInstance).SetResourceInstanceDeposed( - absResource.Resource, - deposedKey, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectTainted, - AttrsJSON: []byte(`{"id":"bar"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - schema := &ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test_instance": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - }, - }, - }, - } - - p := testProvider("test") - p.ConfigureProvider(providers.ConfigureProviderRequest{}) - p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema) - - p.UpgradeResourceStateResponse = &providers.UpgradeResourceStateResponse{ - UpgradedState: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("bar"), - }), - } - ctx := &MockEvalContext{ - StateState: state.SyncWrapper(), - ProviderProvider: p, - ProviderSchemaSchema: schema, - ChangesChanges: plans.NewChanges().SyncWrapper(), - } - - node := NodeDestroyDeposedResourceInstanceObject{ - NodeAbstractResourceInstance: &NodeAbstractResourceInstance{ - Addr: absResource, - NodeAbstractResource: NodeAbstractResource{ - ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - }, - }, - DeposedKey: deposedKey, - } - err := node.Execute(ctx, walkApply) - - if err != nil { - t.Fatalf("unexpected error: %s", err) - } - - if !state.Empty() { - t.Fatalf("resources left in state after destroy") - } -} - -func TestNodeDestroyDeposedResourceInstanceObject_WriteResourceInstanceState(t *testing.T) { - state := states.NewState() - ctx := new(MockEvalContext) - ctx.StateState = state.SyncWrapper() - ctx.PathPath = addrs.RootModuleInstance - mockProvider := mockProviderWithResourceTypeSchema("aws_instance", &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Optional: true, - }, - }, - }) - ctx.ProviderProvider = mockProvider - ctx.ProviderSchemaSchema = mockProvider.ProviderSchema() - - obj := &states.ResourceInstanceObject{ - Value: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("i-abc123"), - }), - Status: states.ObjectReady, - } - node := &NodeDestroyDeposedResourceInstanceObject{ - NodeAbstractResourceInstance: &NodeAbstractResourceInstance{ - NodeAbstractResource: NodeAbstractResource{ - ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - }, - Addr: mustResourceInstanceAddr("aws_instance.foo"), - }, - DeposedKey: states.NewDeposedKey(), - } - err := node.writeResourceInstanceState(ctx, obj) - if err != nil { - t.Fatalf("unexpected error: %s", err.Error()) - } - - checkStateString(t, state, ` -aws_instance.foo: (1 deposed) - ID = - provider = provider["registry.terraform.io/hashicorp/aws"] - Deposed ID 1 = i-abc123 - `) -} - -func TestNodeDestroyDeposedResourceInstanceObject_ExecuteMissingState(t *testing.T) { - p := simpleMockProvider() - ctx := &MockEvalContext{ - StateState: states.NewState().SyncWrapper(), - ProviderProvider: simpleMockProvider(), - ProviderSchemaSchema: p.ProviderSchema(), - ChangesChanges: plans.NewChanges().SyncWrapper(), - } - - node := NodeDestroyDeposedResourceInstanceObject{ - NodeAbstractResourceInstance: &NodeAbstractResourceInstance{ - Addr: mustResourceInstanceAddr("test_object.foo"), - NodeAbstractResource: NodeAbstractResource{ - ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - }, - }, - DeposedKey: states.NewDeposedKey(), - } - err := node.Execute(ctx, walkApply) - - if err == nil { - t.Fatal("expected error") - } -} diff --git a/internal/terraform/node_resource_import.go b/internal/terraform/node_resource_import.go deleted file mode 100644 index 93b14fdf18a6..000000000000 --- a/internal/terraform/node_resource_import.go +++ /dev/null @@ -1,251 +0,0 @@ -package terraform - -import ( - "fmt" - "log" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -type graphNodeImportState struct { - Addr addrs.AbsResourceInstance // Addr is the resource address to import into - ID string // ID is the ID to import as - ProviderAddr addrs.AbsProviderConfig // Provider address given by the user, or implied by the resource type - ResolvedProvider addrs.AbsProviderConfig // provider node address after resolution - - states []providers.ImportedResource -} - -var ( - _ GraphNodeModulePath = (*graphNodeImportState)(nil) - _ GraphNodeExecutable = (*graphNodeImportState)(nil) - _ GraphNodeProviderConsumer = (*graphNodeImportState)(nil) - _ GraphNodeDynamicExpandable = (*graphNodeImportState)(nil) -) - -func (n *graphNodeImportState) Name() string { - return fmt.Sprintf("%s (import id %q)", n.Addr, n.ID) -} - -// GraphNodeProviderConsumer -func (n *graphNodeImportState) ProvidedBy() (addrs.ProviderConfig, bool) { - // We assume that n.ProviderAddr has been properly populated here. - // It's the responsibility of the code creating a graphNodeImportState - // to populate this, possibly by calling DefaultProviderConfig() on the - // resource address to infer an implied provider from the resource type - // name. - return n.ProviderAddr, false -} - -// GraphNodeProviderConsumer -func (n *graphNodeImportState) Provider() addrs.Provider { - // We assume that n.ProviderAddr has been properly populated here. - // It's the responsibility of the code creating a graphNodeImportState - // to populate this, possibly by calling DefaultProviderConfig() on the - // resource address to infer an implied provider from the resource type - // name. - return n.ProviderAddr.Provider -} - -// GraphNodeProviderConsumer -func (n *graphNodeImportState) SetProvider(addr addrs.AbsProviderConfig) { - n.ResolvedProvider = addr -} - -// GraphNodeModuleInstance -func (n *graphNodeImportState) Path() addrs.ModuleInstance { - return n.Addr.Module -} - -// GraphNodeModulePath -func (n *graphNodeImportState) ModulePath() addrs.Module { - return n.Addr.Module.Module() -} - -// GraphNodeExecutable impl. -func (n *graphNodeImportState) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) { - // Reset our states - n.states = nil - - provider, _, err := getProvider(ctx, n.ResolvedProvider) - diags = diags.Append(err) - if diags.HasErrors() { - return diags - } - - // import state - absAddr := n.Addr.Resource.Absolute(ctx.Path()) - - // Call pre-import hook - diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) { - return h.PreImportState(absAddr, n.ID) - })) - if diags.HasErrors() { - return diags - } - - resp := provider.ImportResourceState(providers.ImportResourceStateRequest{ - TypeName: n.Addr.Resource.Resource.Type, - ID: n.ID, - }) - diags = diags.Append(resp.Diagnostics) - if diags.HasErrors() { - return diags - } - - imported := resp.ImportedResources - for _, obj := range imported { - log.Printf("[TRACE] graphNodeImportState: import %s %q produced instance object of type %s", absAddr.String(), n.ID, obj.TypeName) - } - n.states = imported - - // Call post-import hook - diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) { - return h.PostImportState(absAddr, imported) - })) - return diags -} - -// GraphNodeDynamicExpandable impl. -// -// We use DynamicExpand as a way to generate the subgraph of refreshes -// and state inserts we need to do for our import state. Since they're new -// resources they don't depend on anything else and refreshes are isolated -// so this is nearly a perfect use case for dynamic expand. -func (n *graphNodeImportState) DynamicExpand(ctx EvalContext) (*Graph, error) { - var diags tfdiags.Diagnostics - - g := &Graph{Path: ctx.Path()} - - // nameCounter is used to de-dup names in the state. - nameCounter := make(map[string]int) - - // Compile the list of addresses that we'll be inserting into the state. - // We do this ahead of time so we can verify that we aren't importing - // something that already exists. - addrs := make([]addrs.AbsResourceInstance, len(n.states)) - for i, state := range n.states { - addr := n.Addr - if t := state.TypeName; t != "" { - addr.Resource.Resource.Type = t - } - - // Determine if we need to suffix the name to de-dup - key := addr.String() - count, ok := nameCounter[key] - if ok { - count++ - addr.Resource.Resource.Name += fmt.Sprintf("-%d", count) - } - nameCounter[key] = count - - // Add it to our list - addrs[i] = addr - } - - // Verify that all the addresses are clear - state := ctx.State() - for _, addr := range addrs { - existing := state.ResourceInstance(addr) - if existing != nil { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Resource already managed by Terraform", - fmt.Sprintf("Terraform is already managing a remote object for %s. To import to this address you must first remove the existing object from the state.", addr), - )) - continue - } - } - if diags.HasErrors() { - // Bail out early, then. - return nil, diags.Err() - } - - // For each of the states, we add a node to handle the refresh/add to state. - // "n.states" is populated by our own Execute with the result of - // ImportState. Since DynamicExpand is always called after Execute, this is - // safe. - for i, state := range n.states { - g.Add(&graphNodeImportStateSub{ - TargetAddr: addrs[i], - State: state, - ResolvedProvider: n.ResolvedProvider, - }) - } - - addRootNodeToGraph(g) - - // Done! - return g, diags.Err() -} - -// graphNodeImportStateSub is the sub-node of graphNodeImportState -// and is part of the subgraph. This node is responsible for refreshing -// and adding a resource to the state once it is imported. -type graphNodeImportStateSub struct { - TargetAddr addrs.AbsResourceInstance - State providers.ImportedResource - ResolvedProvider addrs.AbsProviderConfig -} - -var ( - _ GraphNodeModuleInstance = (*graphNodeImportStateSub)(nil) - _ GraphNodeExecutable = (*graphNodeImportStateSub)(nil) -) - -func (n *graphNodeImportStateSub) Name() string { - return fmt.Sprintf("import %s result", n.TargetAddr) -} - -func (n *graphNodeImportStateSub) Path() addrs.ModuleInstance { - return n.TargetAddr.Module -} - -// GraphNodeExecutable impl. -func (n *graphNodeImportStateSub) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) { - // If the Ephemeral type isn't set, then it is an error - if n.State.TypeName == "" { - diags = diags.Append(fmt.Errorf("import of %s didn't set type", n.TargetAddr.String())) - return diags - } - - state := n.State.AsInstanceObject() - - // Refresh - riNode := &NodeAbstractResourceInstance{ - Addr: n.TargetAddr, - NodeAbstractResource: NodeAbstractResource{ - ResolvedProvider: n.ResolvedProvider, - }, - } - state, refreshDiags := riNode.refresh(ctx, states.NotDeposed, state) - diags = diags.Append(refreshDiags) - if diags.HasErrors() { - return diags - } - - // Verify the existance of the imported resource - if state.Value.IsNull() { - var diags tfdiags.Diagnostics - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Cannot import non-existent remote object", - fmt.Sprintf( - "While attempting to import an existing object to %q, "+ - "the provider detected that no object exists with the given id. "+ - "Only pre-existing objects can be imported; check that the id "+ - "is correct and that it is associated with the provider's "+ - "configured region or endpoint, or use \"terraform apply\" to "+ - "create a new remote object for this resource.", - n.TargetAddr, - ), - )) - return diags - } - - diags = diags.Append(riNode.writeResourceInstanceState(ctx, state, workingState)) - return diags -} diff --git a/internal/terraform/node_resource_plan.go b/internal/terraform/node_resource_plan.go deleted file mode 100644 index 3d9d201f349c..000000000000 --- a/internal/terraform/node_resource_plan.go +++ /dev/null @@ -1,402 +0,0 @@ -package terraform - -import ( - "fmt" - "log" - "strings" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/dag" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -// nodeExpandPlannableResource represents an addrs.ConfigResource and implements -// DynamicExpand to a subgraph containing all of the addrs.AbsResourceInstance -// resulting from both the containing module and resource-specific expansion. -type nodeExpandPlannableResource struct { - *NodeAbstractResource - - // ForceCreateBeforeDestroy might be set via our GraphNodeDestroyerCBD - // during graph construction, if dependencies require us to force this - // on regardless of what the configuration says. - ForceCreateBeforeDestroy *bool - - // skipRefresh indicates that we should skip refreshing individual instances - skipRefresh bool - - preDestroyRefresh bool - - // skipPlanChanges indicates we should skip trying to plan change actions - // for any instances. - skipPlanChanges bool - - // forceReplace are resource instance addresses where the user wants to - // force generating a replace action. This set isn't pre-filtered, so - // it might contain addresses that have nothing to do with the resource - // that this node represents, which the node itself must therefore ignore. - forceReplace []addrs.AbsResourceInstance - - // We attach dependencies to the Resource during refresh, since the - // instances are instantiated during DynamicExpand. - // FIXME: These would be better off converted to a generic Set data - // structure in the future, as we need to compare for equality and take the - // union of multiple groups of dependencies. - dependencies []addrs.ConfigResource -} - -var ( - _ GraphNodeDestroyerCBD = (*nodeExpandPlannableResource)(nil) - _ GraphNodeDynamicExpandable = (*nodeExpandPlannableResource)(nil) - _ GraphNodeReferenceable = (*nodeExpandPlannableResource)(nil) - _ GraphNodeReferencer = (*nodeExpandPlannableResource)(nil) - _ GraphNodeConfigResource = (*nodeExpandPlannableResource)(nil) - _ GraphNodeAttachResourceConfig = (*nodeExpandPlannableResource)(nil) - _ GraphNodeAttachDependencies = (*nodeExpandPlannableResource)(nil) - _ GraphNodeTargetable = (*nodeExpandPlannableResource)(nil) - _ graphNodeExpandsInstances = (*nodeExpandPlannableResource)(nil) -) - -func (n *nodeExpandPlannableResource) Name() string { - return n.NodeAbstractResource.Name() + " (expand)" -} - -func (n *nodeExpandPlannableResource) expandsInstances() { -} - -// GraphNodeAttachDependencies -func (n *nodeExpandPlannableResource) AttachDependencies(deps []addrs.ConfigResource) { - n.dependencies = deps -} - -// GraphNodeDestroyerCBD -func (n *nodeExpandPlannableResource) CreateBeforeDestroy() bool { - if n.ForceCreateBeforeDestroy != nil { - return *n.ForceCreateBeforeDestroy - } - - // If we have no config, we just assume no - if n.Config == nil || n.Config.Managed == nil { - return false - } - - return n.Config.Managed.CreateBeforeDestroy -} - -// GraphNodeDestroyerCBD -func (n *nodeExpandPlannableResource) ModifyCreateBeforeDestroy(v bool) error { - n.ForceCreateBeforeDestroy = &v - return nil -} - -func (n *nodeExpandPlannableResource) DynamicExpand(ctx EvalContext) (*Graph, error) { - var g Graph - - expander := ctx.InstanceExpander() - moduleInstances := expander.ExpandModule(n.Addr.Module) - - // Lock the state while we inspect it - state := ctx.State().Lock() - - var orphans []*states.Resource - for _, res := range state.Resources(n.Addr) { - found := false - for _, m := range moduleInstances { - if m.Equal(res.Addr.Module) { - found = true - break - } - } - // The module instance of the resource in the state doesn't exist - // in the current config, so this whole resource is orphaned. - if !found { - orphans = append(orphans, res) - } - } - - // We'll no longer use the state directly here, and the other functions - // we'll call below may use it so we'll release the lock. - state = nil - ctx.State().Unlock() - - // The concrete resource factory we'll use for orphans - concreteResourceOrphan := func(a *NodeAbstractResourceInstance) *NodePlannableResourceInstanceOrphan { - // Add the config and state since we don't do that via transforms - a.Config = n.Config - a.ResolvedProvider = n.ResolvedProvider - a.Schema = n.Schema - a.ProvisionerSchemas = n.ProvisionerSchemas - a.ProviderMetas = n.ProviderMetas - a.Dependencies = n.dependencies - - return &NodePlannableResourceInstanceOrphan{ - NodeAbstractResourceInstance: a, - skipRefresh: n.skipRefresh, - skipPlanChanges: n.skipPlanChanges, - } - } - - for _, res := range orphans { - for key := range res.Instances { - addr := res.Addr.Instance(key) - abs := NewNodeAbstractResourceInstance(addr) - abs.AttachResourceState(res) - n := concreteResourceOrphan(abs) - g.Add(n) - } - } - - // The above dealt with the expansion of the containing module, so now - // we need to deal with the expansion of the resource itself across all - // instances of the module. - // - // We'll gather up all of the leaf instances we learn about along the way - // so that we can inform the checks subsystem of which instances it should - // be expecting check results for, below. - var diags tfdiags.Diagnostics - instAddrs := addrs.MakeSet[addrs.Checkable]() - for _, module := range moduleInstances { - resAddr := n.Addr.Resource.Absolute(module) - err := n.expandResourceInstances(ctx, resAddr, &g, instAddrs) - diags = diags.Append(err) - } - if diags.HasErrors() { - return nil, diags.ErrWithWarnings() - } - - // If this is a resource that participates in custom condition checks - // (i.e. it has preconditions or postconditions) then the check state - // wants to know the addresses of the checkable objects so that it can - // treat them as unknown status if we encounter an error before actually - // visiting the checks. - if checkState := ctx.Checks(); checkState.ConfigHasChecks(n.NodeAbstractResource.Addr) { - checkState.ReportCheckableObjects(n.NodeAbstractResource.Addr, instAddrs) - } - - addRootNodeToGraph(&g) - - return &g, diags.ErrWithWarnings() -} - -// expandResourceInstances calculates the dynamic expansion for the resource -// itself in the context of a particular module instance. -// -// It has several side-effects: -// - Adds a node to Graph g for each leaf resource instance it discovers, whether present or orphaned. -// - Registers the expansion of the resource in the "expander" object embedded inside EvalContext ctx. -// - Adds each present (non-orphaned) resource instance address to instAddrs (guaranteed to always be addrs.AbsResourceInstance, despite being declared as addrs.Checkable). -// -// After calling this for each of the module instances the resource appears -// within, the caller must register the final superset instAddrs with the -// checks subsystem so that it knows the fully expanded set of checkable -// object instances for this resource instance. -func (n *nodeExpandPlannableResource) expandResourceInstances(globalCtx EvalContext, resAddr addrs.AbsResource, g *Graph, instAddrs addrs.Set[addrs.Checkable]) error { - var diags tfdiags.Diagnostics - - if n.Config == nil { - // Nothing to do, then. - log.Printf("[TRACE] nodeExpandPlannableResource: no configuration present for %s", n.Name()) - return diags.ErrWithWarnings() - } - - // The rest of our work here needs to know which module instance it's - // working in, so that it can evaluate expressions in the appropriate scope. - moduleCtx := globalCtx.WithPath(resAddr.Module) - - // writeResourceState is responsible for informing the expander of what - // repetition mode this resource has, which allows expander.ExpandResource - // to work below. - moreDiags := n.writeResourceState(moduleCtx, resAddr) - diags = diags.Append(moreDiags) - if moreDiags.HasErrors() { - return diags.ErrWithWarnings() - } - - // Before we expand our resource into potentially many resource instances, - // we'll verify that any mention of this resource in n.forceReplace is - // consistent with the repetition mode of the resource. In other words, - // we're aiming to catch a situation where naming a particular resource - // instance would require an instance key but the given address has none. - expander := moduleCtx.InstanceExpander() - instanceAddrs := expander.ExpandResource(resAddr) - - // If there's a number of instances other than 1 then we definitely need - // an index. - mustHaveIndex := len(instanceAddrs) != 1 - // If there's only one instance then we might still need an index, if the - // instance address has one. - if len(instanceAddrs) == 1 && instanceAddrs[0].Resource.Key != addrs.NoKey { - mustHaveIndex = true - } - if mustHaveIndex { - for _, candidateAddr := range n.forceReplace { - if candidateAddr.Resource.Key == addrs.NoKey { - if n.Addr.Resource.Equal(candidateAddr.Resource.Resource) { - switch { - case len(instanceAddrs) == 0: - // In this case there _are_ no instances to replace, so - // there isn't any alternative address for us to suggest. - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Warning, - "Incompletely-matched force-replace resource instance", - fmt.Sprintf( - "Your force-replace request for %s doesn't match any resource instances because this resource doesn't have any instances.", - candidateAddr, - ), - )) - case len(instanceAddrs) == 1: - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Warning, - "Incompletely-matched force-replace resource instance", - fmt.Sprintf( - "Your force-replace request for %s doesn't match any resource instances because it lacks an instance key.\n\nTo force replacement of the single declared instance, use the following option instead:\n -replace=%q", - candidateAddr, instanceAddrs[0], - ), - )) - default: - var possibleValidOptions strings.Builder - for _, addr := range instanceAddrs { - fmt.Fprintf(&possibleValidOptions, "\n -replace=%q", addr) - } - - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Warning, - "Incompletely-matched force-replace resource instance", - fmt.Sprintf( - "Your force-replace request for %s doesn't match any resource instances because it lacks an instance key.\n\nTo force replacement of particular instances, use one or more of the following options instead:%s", - candidateAddr, possibleValidOptions.String(), - ), - )) - } - } - } - } - } - // NOTE: The actual interpretation of n.forceReplace to produce replace - // actions is in the per-instance function we're about to call, because - // we need to evaluate it on a per-instance basis. - - for _, addr := range instanceAddrs { - // If this resource is participating in the "checks" mechanism then our - // caller will need to know all of our expanded instance addresses as - // checkable object instances. - // (NOTE: instAddrs probably already has other instance addresses in it - // from earlier calls to this function with different resource addresses, - // because its purpose is to aggregate them all together into a single set.) - instAddrs.Add(addr) - } - - // Our graph builder mechanism expects to always be constructing new - // graphs rather than adding to existing ones, so we'll first - // construct a subgraph just for this individual modules's instances and - // then we'll steal all of its nodes and edges to incorporate into our - // main graph which contains all of the resource instances together. - instG, err := n.resourceInstanceSubgraph(moduleCtx, resAddr, instanceAddrs) - if err != nil { - diags = diags.Append(err) - return diags.ErrWithWarnings() - } - g.Subsume(&instG.AcyclicGraph.Graph) - - return diags.ErrWithWarnings() -} - -func (n *nodeExpandPlannableResource) resourceInstanceSubgraph(ctx EvalContext, addr addrs.AbsResource, instanceAddrs []addrs.AbsResourceInstance) (*Graph, error) { - var diags tfdiags.Diagnostics - - // Our graph transformers require access to the full state, so we'll - // temporarily lock it while we work on this. - state := ctx.State().Lock() - defer ctx.State().Unlock() - - // The concrete resource factory we'll use - concreteResource := func(a *NodeAbstractResourceInstance) dag.Vertex { - // check if this node is being imported first - for _, importTarget := range n.importTargets { - if importTarget.Addr.Equal(a.Addr) { - return &graphNodeImportState{ - Addr: importTarget.Addr, - ID: importTarget.ID, - ResolvedProvider: n.ResolvedProvider, - } - } - } - - // Add the config and state since we don't do that via transforms - a.Config = n.Config - a.ResolvedProvider = n.ResolvedProvider - a.Schema = n.Schema - a.ProvisionerSchemas = n.ProvisionerSchemas - a.ProviderMetas = n.ProviderMetas - a.dependsOn = n.dependsOn - a.Dependencies = n.dependencies - a.preDestroyRefresh = n.preDestroyRefresh - - return &NodePlannableResourceInstance{ - NodeAbstractResourceInstance: a, - - // By the time we're walking, we've figured out whether we need - // to force on CreateBeforeDestroy due to dependencies on other - // nodes that have it. - ForceCreateBeforeDestroy: n.CreateBeforeDestroy(), - skipRefresh: n.skipRefresh, - skipPlanChanges: n.skipPlanChanges, - forceReplace: n.forceReplace, - } - } - - // The concrete resource factory we'll use for orphans - concreteResourceOrphan := func(a *NodeAbstractResourceInstance) dag.Vertex { - // Add the config and state since we don't do that via transforms - a.Config = n.Config - a.ResolvedProvider = n.ResolvedProvider - a.Schema = n.Schema - a.ProvisionerSchemas = n.ProvisionerSchemas - a.ProviderMetas = n.ProviderMetas - - return &NodePlannableResourceInstanceOrphan{ - NodeAbstractResourceInstance: a, - skipRefresh: n.skipRefresh, - skipPlanChanges: n.skipPlanChanges, - } - } - - // Start creating the steps - steps := []GraphTransformer{ - // Expand the count or for_each (if present) - &ResourceCountTransformer{ - Concrete: concreteResource, - Schema: n.Schema, - Addr: n.ResourceAddr(), - InstanceAddrs: instanceAddrs, - }, - - // Add the count/for_each orphans - &OrphanResourceInstanceCountTransformer{ - Concrete: concreteResourceOrphan, - Addr: addr, - InstanceAddrs: instanceAddrs, - State: state, - }, - - // Attach the state - &AttachStateTransformer{State: state}, - - // Targeting - &TargetsTransformer{Targets: n.Targets}, - - // Connect references so ordering is correct - &ReferenceTransformer{}, - - // Make sure there is a single root - &RootTransformer{}, - } - - // Build the graph - b := &BasicGraphBuilder{ - Steps: steps, - Name: "nodeExpandPlannableResource", - } - graph, diags := b.Build(addr.Module) - return graph, diags.ErrWithWarnings() -} diff --git a/internal/terraform/node_resource_plan_destroy.go b/internal/terraform/node_resource_plan_destroy.go deleted file mode 100644 index dd8216445d32..000000000000 --- a/internal/terraform/node_resource_plan_destroy.go +++ /dev/null @@ -1,122 +0,0 @@ -package terraform - -import ( - "fmt" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" - "github.com/zclconf/go-cty/cty" -) - -// NodePlanDestroyableResourceInstance represents a resource that is ready -// to be planned for destruction. -type NodePlanDestroyableResourceInstance struct { - *NodeAbstractResourceInstance - - // skipRefresh indicates that we should skip refreshing - skipRefresh bool -} - -var ( - _ GraphNodeModuleInstance = (*NodePlanDestroyableResourceInstance)(nil) - _ GraphNodeReferenceable = (*NodePlanDestroyableResourceInstance)(nil) - _ GraphNodeReferencer = (*NodePlanDestroyableResourceInstance)(nil) - _ GraphNodeDestroyer = (*NodePlanDestroyableResourceInstance)(nil) - _ GraphNodeConfigResource = (*NodePlanDestroyableResourceInstance)(nil) - _ GraphNodeResourceInstance = (*NodePlanDestroyableResourceInstance)(nil) - _ GraphNodeAttachResourceConfig = (*NodePlanDestroyableResourceInstance)(nil) - _ GraphNodeAttachResourceState = (*NodePlanDestroyableResourceInstance)(nil) - _ GraphNodeExecutable = (*NodePlanDestroyableResourceInstance)(nil) - _ GraphNodeProviderConsumer = (*NodePlanDestroyableResourceInstance)(nil) -) - -// GraphNodeDestroyer -func (n *NodePlanDestroyableResourceInstance) DestroyAddr() *addrs.AbsResourceInstance { - addr := n.ResourceInstanceAddr() - return &addr -} - -// GraphNodeEvalable -func (n *NodePlanDestroyableResourceInstance) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) { - addr := n.ResourceInstanceAddr() - - switch addr.Resource.Resource.Mode { - case addrs.ManagedResourceMode: - return n.managedResourceExecute(ctx, op) - case addrs.DataResourceMode: - return n.dataResourceExecute(ctx, op) - default: - panic(fmt.Errorf("unsupported resource mode %s", n.Config.Mode)) - } -} - -func (n *NodePlanDestroyableResourceInstance) managedResourceExecute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) { - addr := n.ResourceInstanceAddr() - - // Declare a bunch of variables that are used for state during - // evaluation. These are written to by address in the EvalNodes we - // declare below. - var change *plans.ResourceInstanceChange - var state *states.ResourceInstanceObject - - state, err := n.readResourceInstanceState(ctx, addr) - diags = diags.Append(err) - if diags.HasErrors() { - return diags - } - - // If we are in the "skip refresh" mode then we will have skipped over our - // usual opportunity to update the previous run state and refresh state - // with the result of any provider schema upgrades, so we'll compensate - // by doing that here. - // - // NOTE: this is coupled with logic in Context.destroyPlan which skips - // running a normal plan walk when refresh is enabled. These two - // conditionals must agree (be exactly opposite) in order to get the - // correct behavior in both cases. - if n.skipRefresh { - diags = diags.Append(n.writeResourceInstanceState(ctx, state, prevRunState)) - if diags.HasErrors() { - return diags - } - diags = diags.Append(n.writeResourceInstanceState(ctx, state, refreshState)) - if diags.HasErrors() { - return diags - } - } - - change, destroyPlanDiags := n.planDestroy(ctx, state, "") - diags = diags.Append(destroyPlanDiags) - if diags.HasErrors() { - return diags - } - - diags = diags.Append(n.checkPreventDestroy(change)) - if diags.HasErrors() { - return diags - } - - diags = diags.Append(n.writeChange(ctx, change, "")) - return diags -} - -func (n *NodePlanDestroyableResourceInstance) dataResourceExecute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) { - - // We may not be able to read a prior data source from the state if the - // schema was upgraded and we are destroying before ever refreshing that - // data source. Regardless, a data source "destroy" is simply writing a - // null state, which we can do with a null prior state too. - change := &plans.ResourceInstanceChange{ - Addr: n.ResourceInstanceAddr(), - PrevRunAddr: n.prevRunAddr(ctx), - Change: plans.Change{ - Action: plans.Delete, - Before: cty.NullVal(cty.DynamicPseudoType), - After: cty.NullVal(cty.DynamicPseudoType), - }, - ProviderAddr: n.ResolvedProvider, - } - return diags.Append(n.writeChange(ctx, change, "")) -} diff --git a/internal/terraform/node_resource_plan_instance.go b/internal/terraform/node_resource_plan_instance.go deleted file mode 100644 index aac13bedc82d..000000000000 --- a/internal/terraform/node_resource_plan_instance.go +++ /dev/null @@ -1,422 +0,0 @@ -package terraform - -import ( - "fmt" - "log" - "sort" - - "github.com/hashicorp/terraform/internal/instances" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" - "github.com/zclconf/go-cty/cty" - - "github.com/hashicorp/terraform/internal/addrs" -) - -// NodePlannableResourceInstance represents a _single_ resource -// instance that is plannable. This means this represents a single -// count index, for example. -type NodePlannableResourceInstance struct { - *NodeAbstractResourceInstance - ForceCreateBeforeDestroy bool - - // skipRefresh indicates that we should skip refreshing individual instances - skipRefresh bool - - // skipPlanChanges indicates we should skip trying to plan change actions - // for any instances. - skipPlanChanges bool - - // forceReplace are resource instance addresses where the user wants to - // force generating a replace action. This set isn't pre-filtered, so - // it might contain addresses that have nothing to do with the resource - // that this node represents, which the node itself must therefore ignore. - forceReplace []addrs.AbsResourceInstance - - // replaceTriggeredBy stores references from replace_triggered_by which - // triggered this instance to be replaced. - replaceTriggeredBy []*addrs.Reference -} - -var ( - _ GraphNodeModuleInstance = (*NodePlannableResourceInstance)(nil) - _ GraphNodeReferenceable = (*NodePlannableResourceInstance)(nil) - _ GraphNodeReferencer = (*NodePlannableResourceInstance)(nil) - _ GraphNodeConfigResource = (*NodePlannableResourceInstance)(nil) - _ GraphNodeResourceInstance = (*NodePlannableResourceInstance)(nil) - _ GraphNodeAttachResourceConfig = (*NodePlannableResourceInstance)(nil) - _ GraphNodeAttachResourceState = (*NodePlannableResourceInstance)(nil) - _ GraphNodeExecutable = (*NodePlannableResourceInstance)(nil) -) - -// GraphNodeEvalable -func (n *NodePlannableResourceInstance) Execute(ctx EvalContext, op walkOperation) tfdiags.Diagnostics { - addr := n.ResourceInstanceAddr() - - // Eval info is different depending on what kind of resource this is - switch addr.Resource.Resource.Mode { - case addrs.ManagedResourceMode: - return n.managedResourceExecute(ctx) - case addrs.DataResourceMode: - return n.dataResourceExecute(ctx) - default: - panic(fmt.Errorf("unsupported resource mode %s", n.Config.Mode)) - } -} - -func (n *NodePlannableResourceInstance) dataResourceExecute(ctx EvalContext) (diags tfdiags.Diagnostics) { - config := n.Config - addr := n.ResourceInstanceAddr() - - var change *plans.ResourceInstanceChange - - _, providerSchema, err := getProvider(ctx, n.ResolvedProvider) - diags = diags.Append(err) - if diags.HasErrors() { - return diags - } - - diags = diags.Append(validateSelfRef(addr.Resource, config.Config, providerSchema)) - if diags.HasErrors() { - return diags - } - - checkRuleSeverity := tfdiags.Error - if n.skipPlanChanges || n.preDestroyRefresh { - checkRuleSeverity = tfdiags.Warning - } - - change, state, repeatData, planDiags := n.planDataSource(ctx, checkRuleSeverity, n.skipPlanChanges) - diags = diags.Append(planDiags) - if diags.HasErrors() { - return diags - } - - // write the data source into both the refresh state and the - // working state - diags = diags.Append(n.writeResourceInstanceState(ctx, state, refreshState)) - if diags.HasErrors() { - return diags - } - diags = diags.Append(n.writeResourceInstanceState(ctx, state, workingState)) - if diags.HasErrors() { - return diags - } - - diags = diags.Append(n.writeChange(ctx, change, "")) - - // Post-conditions might block further progress. We intentionally do this - // _after_ writing the state/diff because we want to check against - // the result of the operation, and to fail on future operations - // until the user makes the condition succeed. - checkDiags := evalCheckRules( - addrs.ResourcePostcondition, - n.Config.Postconditions, - ctx, addr, repeatData, - checkRuleSeverity, - ) - diags = diags.Append(checkDiags) - - return diags -} - -func (n *NodePlannableResourceInstance) managedResourceExecute(ctx EvalContext) (diags tfdiags.Diagnostics) { - config := n.Config - addr := n.ResourceInstanceAddr() - - var change *plans.ResourceInstanceChange - var instanceRefreshState *states.ResourceInstanceObject - - checkRuleSeverity := tfdiags.Error - if n.skipPlanChanges || n.preDestroyRefresh { - checkRuleSeverity = tfdiags.Warning - } - - _, providerSchema, err := getProvider(ctx, n.ResolvedProvider) - diags = diags.Append(err) - if diags.HasErrors() { - return diags - } - - diags = diags.Append(validateSelfRef(addr.Resource, config.Config, providerSchema)) - if diags.HasErrors() { - return diags - } - - instanceRefreshState, readDiags := n.readResourceInstanceState(ctx, addr) - diags = diags.Append(readDiags) - if diags.HasErrors() { - return diags - } - - // We'll save a snapshot of what we just read from the state into the - // prevRunState before we do anything else, since this will capture the - // result of any schema upgrading that readResourceInstanceState just did, - // but not include any out-of-band changes we might detect in in the - // refresh step below. - diags = diags.Append(n.writeResourceInstanceState(ctx, instanceRefreshState, prevRunState)) - if diags.HasErrors() { - return diags - } - // Also the refreshState, because that should still reflect schema upgrades - // even if it doesn't reflect upstream changes. - diags = diags.Append(n.writeResourceInstanceState(ctx, instanceRefreshState, refreshState)) - if diags.HasErrors() { - return diags - } - - // In 0.13 we could be refreshing a resource with no config. - // We should be operating on managed resource, but check here to be certain - if n.Config == nil || n.Config.Managed == nil { - log.Printf("[WARN] managedResourceExecute: no Managed config value found in instance state for %q", n.Addr) - } else { - if instanceRefreshState != nil { - instanceRefreshState.CreateBeforeDestroy = n.Config.Managed.CreateBeforeDestroy || n.ForceCreateBeforeDestroy - } - } - - // Refresh, maybe - if !n.skipRefresh { - s, refreshDiags := n.refresh(ctx, states.NotDeposed, instanceRefreshState) - diags = diags.Append(refreshDiags) - if diags.HasErrors() { - return diags - } - - instanceRefreshState = s - - if instanceRefreshState != nil { - // When refreshing we start by merging the stored dependencies and - // the configured dependencies. The configured dependencies will be - // stored to state once the changes are applied. If the plan - // results in no changes, we will re-write these dependencies - // below. - instanceRefreshState.Dependencies = mergeDeps(n.Dependencies, instanceRefreshState.Dependencies) - } - - diags = diags.Append(n.writeResourceInstanceState(ctx, instanceRefreshState, refreshState)) - if diags.HasErrors() { - return diags - } - } - - // Plan the instance, unless we're in the refresh-only mode - if !n.skipPlanChanges { - - // add this instance to n.forceReplace if replacement is triggered by - // another change - repData := instances.RepetitionData{} - switch k := addr.Resource.Key.(type) { - case addrs.IntKey: - repData.CountIndex = k.Value() - case addrs.StringKey: - repData.EachKey = k.Value() - repData.EachValue = cty.DynamicVal - } - - diags = diags.Append(n.replaceTriggered(ctx, repData)) - if diags.HasErrors() { - return diags - } - - change, instancePlanState, repeatData, planDiags := n.plan( - ctx, change, instanceRefreshState, n.ForceCreateBeforeDestroy, n.forceReplace, - ) - diags = diags.Append(planDiags) - if diags.HasErrors() { - return diags - } - - // FIXME: here we udpate the change to reflect the reason for - // replacement, but we still overload forceReplace to get the correct - // change planned. - if len(n.replaceTriggeredBy) > 0 { - change.ActionReason = plans.ResourceInstanceReplaceByTriggers - } - - diags = diags.Append(n.checkPreventDestroy(change)) - if diags.HasErrors() { - return diags - } - - // FIXME: it is currently important that we write resource changes to - // the plan (n.writeChange) before we write the corresponding state - // (n.writeResourceInstanceState). - // - // This is because the planned resource state will normally have the - // status of states.ObjectPlanned, which causes later logic to refer to - // the contents of the plan to retrieve the resource data. Because - // there is no shared lock between these two data structures, reversing - // the order of these writes will cause a brief window of inconsistency - // which can lead to a failed safety check. - // - // Future work should adjust these APIs such that it is impossible to - // update these two data structures incorrectly through any objects - // reachable via the terraform.EvalContext API. - diags = diags.Append(n.writeChange(ctx, change, "")) - - diags = diags.Append(n.writeResourceInstanceState(ctx, instancePlanState, workingState)) - if diags.HasErrors() { - return diags - } - - // If this plan resulted in a NoOp, then apply won't have a chance to make - // any changes to the stored dependencies. Since this is a NoOp we know - // that the stored dependencies will have no effect during apply, and we can - // write them out now. - if change.Action == plans.NoOp && !depsEqual(instanceRefreshState.Dependencies, n.Dependencies) { - // the refresh state will be the final state for this resource, so - // finalize the dependencies here if they need to be updated. - instanceRefreshState.Dependencies = n.Dependencies - diags = diags.Append(n.writeResourceInstanceState(ctx, instanceRefreshState, refreshState)) - if diags.HasErrors() { - return diags - } - } - - // Post-conditions might block completion. We intentionally do this - // _after_ writing the state/diff because we want to check against - // the result of the operation, and to fail on future operations - // until the user makes the condition succeed. - // (Note that some preconditions will end up being skipped during - // planning, because their conditions depend on values not yet known.) - checkDiags := evalCheckRules( - addrs.ResourcePostcondition, - n.Config.Postconditions, - ctx, n.ResourceInstanceAddr(), repeatData, - checkRuleSeverity, - ) - diags = diags.Append(checkDiags) - } else { - // In refresh-only mode we need to evaluate the for-each expression in - // order to supply the value to the pre- and post-condition check - // blocks. This has the unfortunate edge case of a refresh-only plan - // executing with a for-each map which has the same keys but different - // values, which could result in a post-condition check relying on that - // value being inaccurate. Unless we decide to store the value of the - // for-each expression in state, this is unavoidable. - forEach, _ := evaluateForEachExpression(n.Config.ForEach, ctx) - repeatData := EvalDataForInstanceKey(n.ResourceInstanceAddr().Resource.Key, forEach) - - checkDiags := evalCheckRules( - addrs.ResourcePrecondition, - n.Config.Preconditions, - ctx, addr, repeatData, - checkRuleSeverity, - ) - diags = diags.Append(checkDiags) - - // Even if we don't plan changes, we do still need to at least update - // the working state to reflect the refresh result. If not, then e.g. - // any output values refering to this will not react to the drift. - // (Even if we didn't actually refresh above, this will still save - // the result of any schema upgrading we did in readResourceInstanceState.) - diags = diags.Append(n.writeResourceInstanceState(ctx, instanceRefreshState, workingState)) - if diags.HasErrors() { - return diags - } - - // Here we also evaluate post-conditions after updating the working - // state, because we want to check against the result of the refresh. - // Unlike in normal planning mode, these checks are still evaluated - // even if pre-conditions generated diagnostics, because we have no - // planned changes to block. - checkDiags = evalCheckRules( - addrs.ResourcePostcondition, - n.Config.Postconditions, - ctx, addr, repeatData, - checkRuleSeverity, - ) - diags = diags.Append(checkDiags) - } - - return diags -} - -// replaceTriggered checks if this instance needs to be replace due to a change -// in a replace_triggered_by reference. If replacement is required, the -// instance address is added to forceReplace -func (n *NodePlannableResourceInstance) replaceTriggered(ctx EvalContext, repData instances.RepetitionData) tfdiags.Diagnostics { - var diags tfdiags.Diagnostics - - for _, expr := range n.Config.TriggersReplacement { - ref, replace, evalDiags := ctx.EvaluateReplaceTriggeredBy(expr, repData) - diags = diags.Append(evalDiags) - if diags.HasErrors() { - continue - } - - if replace { - // FIXME: forceReplace accomplishes the same goal, however we may - // want to communicate more information about which resource - // triggered the replacement in the plan. - // Rather than further complicating the plan method with more - // options, we can refactor both of these features later. - n.forceReplace = append(n.forceReplace, n.Addr) - log.Printf("[DEBUG] ReplaceTriggeredBy forcing replacement of %s due to change in %s", n.Addr, ref.DisplayString()) - - n.replaceTriggeredBy = append(n.replaceTriggeredBy, ref) - break - } - } - - return diags -} - -// mergeDeps returns the union of 2 sets of dependencies -func mergeDeps(a, b []addrs.ConfigResource) []addrs.ConfigResource { - switch { - case len(a) == 0: - return b - case len(b) == 0: - return a - } - - set := make(map[string]addrs.ConfigResource) - - for _, dep := range a { - set[dep.String()] = dep - } - - for _, dep := range b { - set[dep.String()] = dep - } - - newDeps := make([]addrs.ConfigResource, 0, len(set)) - for _, dep := range set { - newDeps = append(newDeps, dep) - } - - return newDeps -} - -func depsEqual(a, b []addrs.ConfigResource) bool { - if len(a) != len(b) { - return false - } - - // Because we need to sort the deps to compare equality, make shallow - // copies to prevent concurrently modifying the array values on - // dependencies shared between expanded instances. - copyA, copyB := make([]addrs.ConfigResource, len(a)), make([]addrs.ConfigResource, len(b)) - copy(copyA, a) - copy(copyB, b) - a, b = copyA, copyB - - less := func(s []addrs.ConfigResource) func(i, j int) bool { - return func(i, j int) bool { - return s[i].String() < s[j].String() - } - } - - sort.Slice(a, less(a)) - sort.Slice(b, less(b)) - - for i := range a { - if !a[i].Equal(b[i]) { - return false - } - } - return true -} diff --git a/internal/terraform/node_resource_plan_orphan.go b/internal/terraform/node_resource_plan_orphan.go deleted file mode 100644 index c48e55b74fb2..000000000000 --- a/internal/terraform/node_resource_plan_orphan.go +++ /dev/null @@ -1,285 +0,0 @@ -package terraform - -import ( - "fmt" - "log" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -// NodePlannableResourceInstanceOrphan represents a resource that is "applyable": -// it is ready to be applied and is represented by a diff. -type NodePlannableResourceInstanceOrphan struct { - *NodeAbstractResourceInstance - - // skipRefresh indicates that we should skip refreshing individual instances - skipRefresh bool - - // skipPlanChanges indicates we should skip trying to plan change actions - // for any instances. - skipPlanChanges bool -} - -var ( - _ GraphNodeModuleInstance = (*NodePlannableResourceInstanceOrphan)(nil) - _ GraphNodeReferenceable = (*NodePlannableResourceInstanceOrphan)(nil) - _ GraphNodeReferencer = (*NodePlannableResourceInstanceOrphan)(nil) - _ GraphNodeConfigResource = (*NodePlannableResourceInstanceOrphan)(nil) - _ GraphNodeResourceInstance = (*NodePlannableResourceInstanceOrphan)(nil) - _ GraphNodeAttachResourceConfig = (*NodePlannableResourceInstanceOrphan)(nil) - _ GraphNodeAttachResourceState = (*NodePlannableResourceInstanceOrphan)(nil) - _ GraphNodeExecutable = (*NodePlannableResourceInstanceOrphan)(nil) - _ GraphNodeProviderConsumer = (*NodePlannableResourceInstanceOrphan)(nil) -) - -func (n *NodePlannableResourceInstanceOrphan) Name() string { - return n.ResourceInstanceAddr().String() + " (orphan)" -} - -// GraphNodeExecutable -func (n *NodePlannableResourceInstanceOrphan) Execute(ctx EvalContext, op walkOperation) tfdiags.Diagnostics { - addr := n.ResourceInstanceAddr() - - // Eval info is different depending on what kind of resource this is - switch addr.Resource.Resource.Mode { - case addrs.ManagedResourceMode: - return n.managedResourceExecute(ctx) - case addrs.DataResourceMode: - return n.dataResourceExecute(ctx) - default: - panic(fmt.Errorf("unsupported resource mode %s", n.Config.Mode)) - } -} - -func (n *NodePlannableResourceInstanceOrphan) ProvidedBy() (addr addrs.ProviderConfig, exact bool) { - if n.Addr.Resource.Resource.Mode == addrs.DataResourceMode { - // indicate that this node does not require a configured provider - return nil, true - } - return n.NodeAbstractResourceInstance.ProvidedBy() -} - -func (n *NodePlannableResourceInstanceOrphan) dataResourceExecute(ctx EvalContext) tfdiags.Diagnostics { - // A data source that is no longer in the config is removed from the state - log.Printf("[TRACE] NodePlannableResourceInstanceOrphan: removing state object for %s", n.Addr) - - // we need to update both the refresh state to refresh the current data - // source, and the working state for plan-time evaluations. - refreshState := ctx.RefreshState() - refreshState.SetResourceInstanceCurrent(n.Addr, nil, n.ResolvedProvider) - - workingState := ctx.State() - workingState.SetResourceInstanceCurrent(n.Addr, nil, n.ResolvedProvider) - return nil -} - -func (n *NodePlannableResourceInstanceOrphan) managedResourceExecute(ctx EvalContext) (diags tfdiags.Diagnostics) { - addr := n.ResourceInstanceAddr() - - oldState, readDiags := n.readResourceInstanceState(ctx, addr) - diags = diags.Append(readDiags) - if diags.HasErrors() { - return diags - } - - // Note any upgrades that readResourceInstanceState might've done in the - // prevRunState, so that it'll conform to current schema. - diags = diags.Append(n.writeResourceInstanceState(ctx, oldState, prevRunState)) - if diags.HasErrors() { - return diags - } - // Also the refreshState, because that should still reflect schema upgrades - // even if not refreshing. - diags = diags.Append(n.writeResourceInstanceState(ctx, oldState, refreshState)) - if diags.HasErrors() { - return diags - } - - if !n.skipRefresh { - // Refresh this instance even though it is going to be destroyed, in - // order to catch missing resources. If this is a normal plan, - // providers expect a Read request to remove missing resources from the - // plan before apply, and may not handle a missing resource during - // Delete correctly. If this is a simple refresh, Terraform is - // expected to remove the missing resource from the state entirely - refreshedState, refreshDiags := n.refresh(ctx, states.NotDeposed, oldState) - diags = diags.Append(refreshDiags) - if diags.HasErrors() { - return diags - } - - diags = diags.Append(n.writeResourceInstanceState(ctx, refreshedState, refreshState)) - if diags.HasErrors() { - return diags - } - - // If we refreshed then our subsequent planning should be in terms of - // the new object, not the original object. - oldState = refreshedState - } - - // If we're skipping planning, all we need to do is write the state. If the - // refresh indicates the instance no longer exists, there is also nothing - // to plan because there is no longer any state and it doesn't exist in the - // config. - if n.skipPlanChanges || oldState == nil || oldState.Value.IsNull() { - return diags.Append(n.writeResourceInstanceState(ctx, oldState, workingState)) - } - - var change *plans.ResourceInstanceChange - change, destroyPlanDiags := n.planDestroy(ctx, oldState, "") - diags = diags.Append(destroyPlanDiags) - if diags.HasErrors() { - return diags - } - - diags = diags.Append(n.checkPreventDestroy(change)) - if diags.HasErrors() { - return diags - } - - // We might be able to offer an approximate reason for why we are - // planning to delete this object. (This is best-effort; we might - // sometimes not have a reason.) - change.ActionReason = n.deleteActionReason(ctx) - - diags = diags.Append(n.writeChange(ctx, change, "")) - if diags.HasErrors() { - return diags - } - - return diags.Append(n.writeResourceInstanceState(ctx, nil, workingState)) -} - -func (n *NodePlannableResourceInstanceOrphan) deleteActionReason(ctx EvalContext) plans.ResourceInstanceChangeActionReason { - cfg := n.Config - if cfg == nil { - if !n.Addr.Equal(n.prevRunAddr(ctx)) { - // This means the resource was moved - see also - // ResourceInstanceChange.Moved() which calculates - // this the same way. - return plans.ResourceInstanceDeleteBecauseNoMoveTarget - } - - return plans.ResourceInstanceDeleteBecauseNoResourceConfig - } - - // If this is a resource instance inside a module instance that's no - // longer declared then we will have a config (because config isn't - // instance-specific) but the expander will know that our resource - // address's module path refers to an undeclared module instance. - if expander := ctx.InstanceExpander(); expander != nil { // (sometimes nil in MockEvalContext in tests) - validModuleAddr := expander.GetDeepestExistingModuleInstance(n.Addr.Module) - if len(validModuleAddr) != len(n.Addr.Module) { - // If we get here then at least one step in the resource's module - // path is to a module instance that doesn't exist at all, and - // so a missing module instance is the delete reason regardless - // of whether there might _also_ be a change to the resource - // configuration inside the module. (Conceptually the configurations - // inside the non-existing module instance don't exist at all, - // but they end up existing just as an artifact of the - // implementation detail that we detect module instance orphans - // only dynamically.) - return plans.ResourceInstanceDeleteBecauseNoModule - } - } - - switch n.Addr.Resource.Key.(type) { - case nil: // no instance key at all - if cfg.Count != nil || cfg.ForEach != nil { - return plans.ResourceInstanceDeleteBecauseWrongRepetition - } - case addrs.IntKey: - if cfg.Count == nil { - // This resource isn't using "count" at all, then - return plans.ResourceInstanceDeleteBecauseWrongRepetition - } - - expander := ctx.InstanceExpander() - if expander == nil { - break // only for tests that produce an incomplete MockEvalContext - } - insts := expander.ExpandResource(n.Addr.ContainingResource()) - - declared := false - for _, inst := range insts { - if n.Addr.Equal(inst) { - declared = true - } - } - if !declared { - // This instance key is outside of the configured range - return plans.ResourceInstanceDeleteBecauseCountIndex - } - case addrs.StringKey: - if cfg.ForEach == nil { - // This resource isn't using "for_each" at all, then - return plans.ResourceInstanceDeleteBecauseWrongRepetition - } - - expander := ctx.InstanceExpander() - if expander == nil { - break // only for tests that produce an incomplete MockEvalContext - } - insts := expander.ExpandResource(n.Addr.ContainingResource()) - - declared := false - for _, inst := range insts { - if n.Addr.Equal(inst) { - declared = true - } - } - if !declared { - // This instance key is outside of the configured range - return plans.ResourceInstanceDeleteBecauseEachKey - } - } - - // If we get here then the instance key type matches the configured - // repetition mode, and so we need to consider whether the key itself - // is within the range of the repetition construct. - if expander := ctx.InstanceExpander(); expander != nil { // (sometimes nil in MockEvalContext in tests) - // First we'll check whether our containing module instance still - // exists, so we can talk about that differently in the reason. - declared := false - for _, inst := range expander.ExpandModule(n.Addr.Module.Module()) { - if n.Addr.Module.Equal(inst) { - declared = true - break - } - } - if !declared { - return plans.ResourceInstanceDeleteBecauseNoModule - } - - // Now we've proven that we're in a still-existing module instance, - // we'll see if our instance key matches something actually declared. - declared = false - for _, inst := range expander.ExpandResource(n.Addr.ContainingResource()) { - if n.Addr.Equal(inst) { - declared = true - break - } - } - if !declared { - // Because we already checked that the key _type_ was correct - // above, we can assume that any mismatch here is a range error, - // and thus we just need to decide which of the two range - // errors we're going to return. - switch n.Addr.Resource.Key.(type) { - case addrs.IntKey: - return plans.ResourceInstanceDeleteBecauseCountIndex - case addrs.StringKey: - return plans.ResourceInstanceDeleteBecauseEachKey - } - } - } - - // If we didn't find any specific reason to report, we'll report "no reason" - // as a fallback, which means the UI should just state it'll be deleted - // without any explicit reasoning. - return plans.ResourceInstanceChangeNoReason -} diff --git a/internal/terraform/node_resource_plan_orphan_test.go b/internal/terraform/node_resource_plan_orphan_test.go deleted file mode 100644 index 0a29decc5639..000000000000 --- a/internal/terraform/node_resource_plan_orphan_test.go +++ /dev/null @@ -1,210 +0,0 @@ -package terraform - -import ( - "testing" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/instances" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" - "github.com/zclconf/go-cty/cty" -) - -func TestNodeResourcePlanOrphanExecute(t *testing.T) { - state := states.NewState() - state.Module(addrs.RootModuleInstance).SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_object", - Name: "foo", - }.Instance(addrs.NoKey), - &states.ResourceInstanceObjectSrc{ - AttrsFlat: map[string]string{ - "test_string": "foo", - }, - Status: states.ObjectReady, - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("test"), - Module: addrs.RootModule, - }, - ) - - p := simpleMockProvider() - p.ConfigureProvider(providers.ConfigureProviderRequest{}) - ctx := &MockEvalContext{ - StateState: state.SyncWrapper(), - RefreshStateState: state.DeepCopy().SyncWrapper(), - PrevRunStateState: state.DeepCopy().SyncWrapper(), - InstanceExpanderExpander: instances.NewExpander(), - ProviderProvider: p, - ProviderSchemaSchema: &ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test_object": simpleTestSchema(), - }, - }, - ChangesChanges: plans.NewChanges().SyncWrapper(), - } - - node := NodePlannableResourceInstanceOrphan{ - NodeAbstractResourceInstance: &NodeAbstractResourceInstance{ - NodeAbstractResource: NodeAbstractResource{ - ResolvedProvider: addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("test"), - Module: addrs.RootModule, - }, - }, - Addr: mustResourceInstanceAddr("test_object.foo"), - }, - } - diags := node.Execute(ctx, walkApply) - if diags.HasErrors() { - t.Fatalf("unexpected error: %s", diags.Err()) - } - if !state.Empty() { - t.Fatalf("expected empty state, got %s", state.String()) - } -} - -func TestNodeResourcePlanOrphanExecute_alreadyDeleted(t *testing.T) { - addr := addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_object", - Name: "foo", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance) - - state := states.NewState() - state.Module(addrs.RootModuleInstance).SetResourceInstanceCurrent( - addr.Resource, - &states.ResourceInstanceObjectSrc{ - AttrsFlat: map[string]string{ - "test_string": "foo", - }, - Status: states.ObjectReady, - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("test"), - Module: addrs.RootModule, - }, - ) - refreshState := state.DeepCopy() - prevRunState := state.DeepCopy() - changes := plans.NewChanges() - - p := simpleMockProvider() - p.ConfigureProvider(providers.ConfigureProviderRequest{}) - p.ReadResourceResponse = &providers.ReadResourceResponse{ - NewState: cty.NullVal(p.GetProviderSchemaResponse.ResourceTypes["test_string"].Block.ImpliedType()), - } - ctx := &MockEvalContext{ - StateState: state.SyncWrapper(), - RefreshStateState: refreshState.SyncWrapper(), - PrevRunStateState: prevRunState.SyncWrapper(), - InstanceExpanderExpander: instances.NewExpander(), - ProviderProvider: p, - ProviderSchemaSchema: &ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test_object": simpleTestSchema(), - }, - }, - ChangesChanges: changes.SyncWrapper(), - } - - node := NodePlannableResourceInstanceOrphan{ - NodeAbstractResourceInstance: &NodeAbstractResourceInstance{ - NodeAbstractResource: NodeAbstractResource{ - ResolvedProvider: addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("test"), - Module: addrs.RootModule, - }, - }, - Addr: mustResourceInstanceAddr("test_object.foo"), - }, - } - diags := node.Execute(ctx, walkPlan) - if diags.HasErrors() { - t.Fatalf("unexpected error: %s", diags.Err()) - } - if !state.Empty() { - t.Fatalf("expected empty state, got %s", state.String()) - } - - if got := prevRunState.ResourceInstance(addr); got == nil { - t.Errorf("no entry for %s in the prev run state; should still be present", addr) - } - if got := refreshState.ResourceInstance(addr); got != nil { - t.Errorf("refresh state has entry for %s; should've been removed", addr) - } - if got := changes.ResourceInstance(addr); got != nil { - t.Errorf("there should be no change for the %s instance, got %s", addr, got.Action) - } -} - -// This test describes a situation which should not be possible, as this node -// should never work on deposed instances. However, a bug elsewhere resulted in -// this code path being exercised and triggered a panic. As a result, the -// assertions at the end of the test are minimal, as the behaviour (aside from -// not panicking) is unspecified. -func TestNodeResourcePlanOrphanExecute_deposed(t *testing.T) { - addr := addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_object", - Name: "foo", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance) - - state := states.NewState() - state.Module(addrs.RootModuleInstance).SetResourceInstanceDeposed( - addr.Resource, - states.NewDeposedKey(), - &states.ResourceInstanceObjectSrc{ - AttrsFlat: map[string]string{ - "test_string": "foo", - }, - Status: states.ObjectReady, - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("test"), - Module: addrs.RootModule, - }, - ) - refreshState := state.DeepCopy() - prevRunState := state.DeepCopy() - changes := plans.NewChanges() - - p := simpleMockProvider() - p.ConfigureProvider(providers.ConfigureProviderRequest{}) - p.ReadResourceResponse = &providers.ReadResourceResponse{ - NewState: cty.NullVal(p.GetProviderSchemaResponse.ResourceTypes["test_string"].Block.ImpliedType()), - } - ctx := &MockEvalContext{ - StateState: state.SyncWrapper(), - RefreshStateState: refreshState.SyncWrapper(), - PrevRunStateState: prevRunState.SyncWrapper(), - InstanceExpanderExpander: instances.NewExpander(), - ProviderProvider: p, - ProviderSchemaSchema: &ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "test_object": simpleTestSchema(), - }, - }, - ChangesChanges: changes.SyncWrapper(), - } - - node := NodePlannableResourceInstanceOrphan{ - NodeAbstractResourceInstance: &NodeAbstractResourceInstance{ - NodeAbstractResource: NodeAbstractResource{ - ResolvedProvider: addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("test"), - Module: addrs.RootModule, - }, - }, - Addr: mustResourceInstanceAddr("test_object.foo"), - }, - } - diags := node.Execute(ctx, walkPlan) - if diags.HasErrors() { - t.Fatalf("unexpected error: %s", diags.Err()) - } -} diff --git a/internal/terraform/node_resource_validate.go b/internal/terraform/node_resource_validate.go deleted file mode 100644 index a70bcdc4bc85..000000000000 --- a/internal/terraform/node_resource_validate.go +++ /dev/null @@ -1,592 +0,0 @@ -package terraform - -import ( - "fmt" - "strings" - - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/didyoumean" - "github.com/hashicorp/terraform/internal/instances" - "github.com/hashicorp/terraform/internal/lang" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/provisioners" - "github.com/hashicorp/terraform/internal/tfdiags" - "github.com/zclconf/go-cty/cty" -) - -// NodeValidatableResource represents a resource that is used for validation -// only. -type NodeValidatableResource struct { - *NodeAbstractResource -} - -var ( - _ GraphNodeModuleInstance = (*NodeValidatableResource)(nil) - _ GraphNodeExecutable = (*NodeValidatableResource)(nil) - _ GraphNodeReferenceable = (*NodeValidatableResource)(nil) - _ GraphNodeReferencer = (*NodeValidatableResource)(nil) - _ GraphNodeConfigResource = (*NodeValidatableResource)(nil) - _ GraphNodeAttachResourceConfig = (*NodeValidatableResource)(nil) - _ GraphNodeAttachProviderMetaConfigs = (*NodeValidatableResource)(nil) -) - -func (n *NodeValidatableResource) Path() addrs.ModuleInstance { - // There is no expansion during validation, so we evaluate everything as - // single module instances. - return n.Addr.Module.UnkeyedInstanceShim() -} - -// GraphNodeEvalable -func (n *NodeValidatableResource) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) { - diags = diags.Append(n.validateResource(ctx)) - - diags = diags.Append(n.validateCheckRules(ctx, n.Config)) - - if managed := n.Config.Managed; managed != nil { - // Validate all the provisioners - for _, p := range managed.Provisioners { - if p.Connection == nil { - p.Connection = n.Config.Managed.Connection - } else if n.Config.Managed.Connection != nil { - p.Connection.Config = configs.MergeBodies(n.Config.Managed.Connection.Config, p.Connection.Config) - } - - // Validate Provisioner Config - diags = diags.Append(n.validateProvisioner(ctx, p)) - if diags.HasErrors() { - return diags - } - } - } - return diags -} - -// validateProvisioner validates the configuration of a provisioner belonging to -// a resource. The provisioner config is expected to contain the merged -// connection configurations. -func (n *NodeValidatableResource) validateProvisioner(ctx EvalContext, p *configs.Provisioner) tfdiags.Diagnostics { - var diags tfdiags.Diagnostics - - provisioner, err := ctx.Provisioner(p.Type) - if err != nil { - diags = diags.Append(err) - return diags - } - - if provisioner == nil { - return diags.Append(fmt.Errorf("provisioner %s not initialized", p.Type)) - } - provisionerSchema, err := ctx.ProvisionerSchema(p.Type) - if err != nil { - return diags.Append(fmt.Errorf("failed to read schema for provisioner %s: %s", p.Type, err)) - } - if provisionerSchema == nil { - return diags.Append(fmt.Errorf("provisioner %s has no schema", p.Type)) - } - - // Validate the provisioner's own config first - configVal, _, configDiags := n.evaluateBlock(ctx, p.Config, provisionerSchema) - diags = diags.Append(configDiags) - - if configVal == cty.NilVal { - // Should never happen for a well-behaved EvaluateBlock implementation - return diags.Append(fmt.Errorf("EvaluateBlock returned nil value")) - } - - // Use unmarked value for validate request - unmarkedConfigVal, _ := configVal.UnmarkDeep() - req := provisioners.ValidateProvisionerConfigRequest{ - Config: unmarkedConfigVal, - } - - resp := provisioner.ValidateProvisionerConfig(req) - diags = diags.Append(resp.Diagnostics) - - if p.Connection != nil { - // We can't comprehensively validate the connection config since its - // final structure is decided by the communicator and we can't instantiate - // that until we have a complete instance state. However, we *can* catch - // configuration keys that are not valid for *any* communicator, catching - // typos early rather than waiting until we actually try to run one of - // the resource's provisioners. - _, _, connDiags := n.evaluateBlock(ctx, p.Connection.Config, connectionBlockSupersetSchema) - diags = diags.Append(connDiags) - } - return diags -} - -func (n *NodeValidatableResource) evaluateBlock(ctx EvalContext, body hcl.Body, schema *configschema.Block) (cty.Value, hcl.Body, tfdiags.Diagnostics) { - keyData, selfAddr := n.stubRepetitionData(n.Config.Count != nil, n.Config.ForEach != nil) - - return ctx.EvaluateBlock(body, schema, selfAddr, keyData) -} - -// connectionBlockSupersetSchema is a schema representing the superset of all -// possible arguments for "connection" blocks across all supported connection -// types. -// -// This currently lives here because we've not yet updated our communicator -// subsystem to be aware of schema itself. Once that is done, we can remove -// this and use a type-specific schema from the communicator to validate -// exactly what is expected for a given connection type. -var connectionBlockSupersetSchema = &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - // NOTE: "type" is not included here because it's treated special - // by the config loader and stored away in a separate field. - - // Common attributes for both connection types - "host": { - Type: cty.String, - Required: true, - }, - "type": { - Type: cty.String, - Optional: true, - }, - "user": { - Type: cty.String, - Optional: true, - }, - "password": { - Type: cty.String, - Optional: true, - }, - "port": { - Type: cty.Number, - Optional: true, - }, - "timeout": { - Type: cty.String, - Optional: true, - }, - "script_path": { - Type: cty.String, - Optional: true, - }, - // For type=ssh only (enforced in ssh communicator) - "target_platform": { - Type: cty.String, - Optional: true, - }, - "private_key": { - Type: cty.String, - Optional: true, - }, - "certificate": { - Type: cty.String, - Optional: true, - }, - "host_key": { - Type: cty.String, - Optional: true, - }, - "agent": { - Type: cty.Bool, - Optional: true, - }, - "agent_identity": { - Type: cty.String, - Optional: true, - }, - "proxy_scheme": { - Type: cty.String, - Optional: true, - }, - "proxy_host": { - Type: cty.String, - Optional: true, - }, - "proxy_port": { - Type: cty.Number, - Optional: true, - }, - "proxy_user_name": { - Type: cty.String, - Optional: true, - }, - "proxy_user_password": { - Type: cty.String, - Optional: true, - }, - "bastion_host": { - Type: cty.String, - Optional: true, - }, - "bastion_host_key": { - Type: cty.String, - Optional: true, - }, - "bastion_port": { - Type: cty.Number, - Optional: true, - }, - "bastion_user": { - Type: cty.String, - Optional: true, - }, - "bastion_password": { - Type: cty.String, - Optional: true, - }, - "bastion_private_key": { - Type: cty.String, - Optional: true, - }, - "bastion_certificate": { - Type: cty.String, - Optional: true, - }, - - // For type=winrm only (enforced in winrm communicator) - "https": { - Type: cty.Bool, - Optional: true, - }, - "insecure": { - Type: cty.Bool, - Optional: true, - }, - "cacert": { - Type: cty.String, - Optional: true, - }, - "use_ntlm": { - Type: cty.Bool, - Optional: true, - }, - }, -} - -func (n *NodeValidatableResource) validateResource(ctx EvalContext) tfdiags.Diagnostics { - var diags tfdiags.Diagnostics - - provider, providerSchema, err := getProvider(ctx, n.ResolvedProvider) - diags = diags.Append(err) - if diags.HasErrors() { - return diags - } - if providerSchema == nil { - diags = diags.Append(fmt.Errorf("validateResource has nil schema for %s", n.Addr)) - return diags - } - - keyData := EvalDataForNoInstanceKey - - switch { - case n.Config.Count != nil: - // If the config block has count, we'll evaluate with an unknown - // number as count.index so we can still type check even though - // we won't expand count until the plan phase. - keyData = InstanceKeyEvalData{ - CountIndex: cty.UnknownVal(cty.Number), - } - - // Basic type-checking of the count argument. More complete validation - // of this will happen when we DynamicExpand during the plan walk. - countDiags := validateCount(ctx, n.Config.Count) - diags = diags.Append(countDiags) - - case n.Config.ForEach != nil: - keyData = InstanceKeyEvalData{ - EachKey: cty.UnknownVal(cty.String), - EachValue: cty.UnknownVal(cty.DynamicPseudoType), - } - - // Evaluate the for_each expression here so we can expose the diagnostics - forEachDiags := validateForEach(ctx, n.Config.ForEach) - diags = diags.Append(forEachDiags) - } - - diags = diags.Append(validateDependsOn(ctx, n.Config.DependsOn)) - - // Validate the provider_meta block for the provider this resource - // belongs to, if there is one. - // - // Note: this will return an error for every resource a provider - // uses in a module, if the provider_meta for that module is - // incorrect. The only way to solve this that we've found is to - // insert a new ProviderMeta graph node in the graph, and make all - // that provider's resources in the module depend on the node. That's - // an awful heavy hammer to swing for this feature, which should be - // used only in limited cases with heavy coordination with the - // Terraform team, so we're going to defer that solution for a future - // enhancement to this functionality. - /* - if n.ProviderMetas != nil { - if m, ok := n.ProviderMetas[n.ProviderAddr.ProviderConfig.Type]; ok && m != nil { - // if the provider doesn't support this feature, throw an error - if (*n.ProviderSchema).ProviderMeta == nil { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: fmt.Sprintf("Provider %s doesn't support provider_meta", cfg.ProviderConfigAddr()), - Detail: fmt.Sprintf("The resource %s belongs to a provider that doesn't support provider_meta blocks", n.Addr), - Subject: &m.ProviderRange, - }) - } else { - _, _, metaDiags := ctx.EvaluateBlock(m.Config, (*n.ProviderSchema).ProviderMeta, nil, EvalDataForNoInstanceKey) - diags = diags.Append(metaDiags) - } - } - } - */ - // BUG(paddy): we're not validating provider_meta blocks on EvalValidate right now - // because the ProviderAddr for the resource isn't available on the EvalValidate - // struct. - - // Provider entry point varies depending on resource mode, because - // managed resources and data resources are two distinct concepts - // in the provider abstraction. - switch n.Config.Mode { - case addrs.ManagedResourceMode: - schema, _ := providerSchema.SchemaForResourceType(n.Config.Mode, n.Config.Type) - if schema == nil { - var suggestion string - if dSchema, _ := providerSchema.SchemaForResourceType(addrs.DataResourceMode, n.Config.Type); dSchema != nil { - suggestion = fmt.Sprintf("\n\nDid you intend to use the data source %q? If so, declare this using a \"data\" block instead of a \"resource\" block.", n.Config.Type) - } else if len(providerSchema.ResourceTypes) > 0 { - suggestions := make([]string, 0, len(providerSchema.ResourceTypes)) - for name := range providerSchema.ResourceTypes { - suggestions = append(suggestions, name) - } - if suggestion = didyoumean.NameSuggestion(n.Config.Type, suggestions); suggestion != "" { - suggestion = fmt.Sprintf(" Did you mean %q?", suggestion) - } - } - - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid resource type", - Detail: fmt.Sprintf("The provider %s does not support resource type %q.%s", n.Provider().ForDisplay(), n.Config.Type, suggestion), - Subject: &n.Config.TypeRange, - }) - return diags - } - - configVal, _, valDiags := ctx.EvaluateBlock(n.Config.Config, schema, nil, keyData) - diags = diags.Append(valDiags) - if valDiags.HasErrors() { - return diags - } - - if n.Config.Managed != nil { // can be nil only in tests with poorly-configured mocks - for _, traversal := range n.Config.Managed.IgnoreChanges { - // validate the ignore_changes traversals apply. - moreDiags := schema.StaticValidateTraversal(traversal) - diags = diags.Append(moreDiags) - - // ignore_changes cannot be used for Computed attributes, - // unless they are also Optional. - // If the traversal was valid, convert it to a cty.Path and - // use that to check whether the Attribute is Computed and - // non-Optional. - if !diags.HasErrors() { - path := traversalToPath(traversal) - - attrSchema := schema.AttributeByPath(path) - - if attrSchema != nil && !attrSchema.Optional && attrSchema.Computed { - // ignore_changes uses absolute traversal syntax in config despite - // using relative traversals, so we strip the leading "." added by - // FormatCtyPath for a better error message. - attrDisplayPath := strings.TrimPrefix(tfdiags.FormatCtyPath(path), ".") - - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagWarning, - Summary: "Redundant ignore_changes element", - Detail: fmt.Sprintf("Adding an attribute name to ignore_changes tells Terraform to ignore future changes to the argument in configuration after the object has been created, retaining the value originally configured.\n\nThe attribute %s is decided by the provider alone and therefore there can be no configured value to compare with. Including this attribute in ignore_changes has no effect. Remove the attribute from ignore_changes to quiet this warning.", attrDisplayPath), - Subject: &n.Config.TypeRange, - }) - } - } - } - } - - // Use unmarked value for validate request - unmarkedConfigVal, _ := configVal.UnmarkDeep() - req := providers.ValidateResourceConfigRequest{ - TypeName: n.Config.Type, - Config: unmarkedConfigVal, - } - - resp := provider.ValidateResourceConfig(req) - diags = diags.Append(resp.Diagnostics.InConfigBody(n.Config.Config, n.Addr.String())) - - case addrs.DataResourceMode: - schema, _ := providerSchema.SchemaForResourceType(n.Config.Mode, n.Config.Type) - if schema == nil { - var suggestion string - if dSchema, _ := providerSchema.SchemaForResourceType(addrs.ManagedResourceMode, n.Config.Type); dSchema != nil { - suggestion = fmt.Sprintf("\n\nDid you intend to use the managed resource type %q? If so, declare this using a \"resource\" block instead of a \"data\" block.", n.Config.Type) - } else if len(providerSchema.DataSources) > 0 { - suggestions := make([]string, 0, len(providerSchema.DataSources)) - for name := range providerSchema.DataSources { - suggestions = append(suggestions, name) - } - if suggestion = didyoumean.NameSuggestion(n.Config.Type, suggestions); suggestion != "" { - suggestion = fmt.Sprintf(" Did you mean %q?", suggestion) - } - } - - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid data source", - Detail: fmt.Sprintf("The provider %s does not support data source %q.%s", n.Provider().ForDisplay(), n.Config.Type, suggestion), - Subject: &n.Config.TypeRange, - }) - return diags - } - - configVal, _, valDiags := ctx.EvaluateBlock(n.Config.Config, schema, nil, keyData) - diags = diags.Append(valDiags) - if valDiags.HasErrors() { - return diags - } - - // Use unmarked value for validate request - unmarkedConfigVal, _ := configVal.UnmarkDeep() - req := providers.ValidateDataResourceConfigRequest{ - TypeName: n.Config.Type, - Config: unmarkedConfigVal, - } - - resp := provider.ValidateDataResourceConfig(req) - diags = diags.Append(resp.Diagnostics.InConfigBody(n.Config.Config, n.Addr.String())) - } - - return diags -} - -func (n *NodeValidatableResource) evaluateExpr(ctx EvalContext, expr hcl.Expression, wantTy cty.Type, self addrs.Referenceable, keyData instances.RepetitionData) (cty.Value, tfdiags.Diagnostics) { - var diags tfdiags.Diagnostics - - refs, refDiags := lang.ReferencesInExpr(expr) - diags = diags.Append(refDiags) - - scope := ctx.EvaluationScope(self, keyData) - - hclCtx, moreDiags := scope.EvalContext(refs) - diags = diags.Append(moreDiags) - - result, hclDiags := expr.Value(hclCtx) - diags = diags.Append(hclDiags) - - return result, diags -} - -func (n *NodeValidatableResource) stubRepetitionData(hasCount, hasForEach bool) (instances.RepetitionData, addrs.Referenceable) { - keyData := EvalDataForNoInstanceKey - selfAddr := n.ResourceAddr().Resource.Instance(addrs.NoKey) - - if n.Config.Count != nil { - // For a resource that has count, we allow count.index but don't - // know at this stage what it will return. - keyData = InstanceKeyEvalData{ - CountIndex: cty.UnknownVal(cty.Number), - } - - // "self" can't point to an unknown key, but we'll force it to be - // key 0 here, which should return an unknown value of the - // expected type since none of these elements are known at this - // point anyway. - selfAddr = n.ResourceAddr().Resource.Instance(addrs.IntKey(0)) - } else if n.Config.ForEach != nil { - // For a resource that has for_each, we allow each.value and each.key - // but don't know at this stage what it will return. - keyData = InstanceKeyEvalData{ - EachKey: cty.UnknownVal(cty.String), - EachValue: cty.DynamicVal, - } - - // "self" can't point to an unknown key, but we'll force it to be - // key "" here, which should return an unknown value of the - // expected type since none of these elements are known at - // this point anyway. - selfAddr = n.ResourceAddr().Resource.Instance(addrs.StringKey("")) - } - - return keyData, selfAddr -} - -func (n *NodeValidatableResource) validateCheckRules(ctx EvalContext, config *configs.Resource) tfdiags.Diagnostics { - var diags tfdiags.Diagnostics - - keyData, selfAddr := n.stubRepetitionData(n.Config.Count != nil, n.Config.ForEach != nil) - - for _, cr := range config.Preconditions { - _, conditionDiags := n.evaluateExpr(ctx, cr.Condition, cty.Bool, nil, keyData) - diags = diags.Append(conditionDiags) - - _, errorMessageDiags := n.evaluateExpr(ctx, cr.ErrorMessage, cty.Bool, nil, keyData) - diags = diags.Append(errorMessageDiags) - } - - for _, cr := range config.Postconditions { - _, conditionDiags := n.evaluateExpr(ctx, cr.Condition, cty.Bool, selfAddr, keyData) - diags = diags.Append(conditionDiags) - - _, errorMessageDiags := n.evaluateExpr(ctx, cr.ErrorMessage, cty.Bool, selfAddr, keyData) - diags = diags.Append(errorMessageDiags) - } - - return diags -} - -func validateCount(ctx EvalContext, expr hcl.Expression) (diags tfdiags.Diagnostics) { - val, countDiags := evaluateCountExpressionValue(expr, ctx) - // If the value isn't known then that's the best we can do for now, but - // we'll check more thoroughly during the plan walk - if !val.IsKnown() { - return diags - } - - if countDiags.HasErrors() { - diags = diags.Append(countDiags) - } - - return diags -} - -func validateForEach(ctx EvalContext, expr hcl.Expression) (diags tfdiags.Diagnostics) { - val, forEachDiags := evaluateForEachExpressionValue(expr, ctx, true) - // If the value isn't known then that's the best we can do for now, but - // we'll check more thoroughly during the plan walk - if !val.IsKnown() { - return diags - } - - if forEachDiags.HasErrors() { - diags = diags.Append(forEachDiags) - } - - return diags -} - -func validateDependsOn(ctx EvalContext, dependsOn []hcl.Traversal) (diags tfdiags.Diagnostics) { - for _, traversal := range dependsOn { - ref, refDiags := addrs.ParseRef(traversal) - diags = diags.Append(refDiags) - if !refDiags.HasErrors() && len(ref.Remaining) != 0 { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid depends_on reference", - Detail: "References in depends_on must be to a whole object (resource, etc), not to an attribute of an object.", - Subject: ref.Remaining.SourceRange().Ptr(), - }) - } - - // The ref must also refer to something that exists. To test that, - // we'll just eval it and count on the fact that our evaluator will - // detect references to non-existent objects. - if !diags.HasErrors() { - scope := ctx.EvaluationScope(nil, EvalDataForNoInstanceKey) - if scope != nil { // sometimes nil in tests, due to incomplete mocks - _, refDiags = scope.EvalReference(ref, cty.DynamicPseudoType) - diags = diags.Append(refDiags) - } - } - } - return diags -} diff --git a/internal/terraform/node_resource_validate_test.go b/internal/terraform/node_resource_validate_test.go deleted file mode 100644 index b5b2af74cd29..000000000000 --- a/internal/terraform/node_resource_validate_test.go +++ /dev/null @@ -1,635 +0,0 @@ -package terraform - -import ( - "errors" - "strings" - "testing" - - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/hcl/v2/hcltest" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/lang/marks" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/provisioners" - "github.com/hashicorp/terraform/internal/tfdiags" - "github.com/zclconf/go-cty/cty" -) - -func TestNodeValidatableResource_ValidateProvisioner_valid(t *testing.T) { - ctx := &MockEvalContext{} - ctx.installSimpleEval() - mp := &MockProvisioner{} - ps := &configschema.Block{} - ctx.ProvisionerSchemaSchema = ps - ctx.ProvisionerProvisioner = mp - - pc := &configs.Provisioner{ - Type: "baz", - Config: hcl.EmptyBody(), - Connection: &configs.Connection{ - Config: configs.SynthBody("", map[string]cty.Value{ - "host": cty.StringVal("localhost"), - "type": cty.StringVal("ssh"), - "port": cty.NumberIntVal(10022), - }), - }, - } - - rc := &configs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_foo", - Name: "bar", - Config: configs.SynthBody("", map[string]cty.Value{}), - } - - node := NodeValidatableResource{ - NodeAbstractResource: &NodeAbstractResource{ - Addr: mustConfigResourceAddr("test_foo.bar"), - Config: rc, - }, - } - - diags := node.validateProvisioner(ctx, pc) - if diags.HasErrors() { - t.Fatalf("node.Eval failed: %s", diags.Err()) - } - if !mp.ValidateProvisionerConfigCalled { - t.Fatalf("p.ValidateProvisionerConfig not called") - } -} - -func TestNodeValidatableResource_ValidateProvisioner__warning(t *testing.T) { - ctx := &MockEvalContext{} - ctx.installSimpleEval() - mp := &MockProvisioner{} - ps := &configschema.Block{} - ctx.ProvisionerSchemaSchema = ps - ctx.ProvisionerProvisioner = mp - - pc := &configs.Provisioner{ - Type: "baz", - Config: hcl.EmptyBody(), - } - - rc := &configs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_foo", - Name: "bar", - Config: configs.SynthBody("", map[string]cty.Value{}), - Managed: &configs.ManagedResource{}, - } - - node := NodeValidatableResource{ - NodeAbstractResource: &NodeAbstractResource{ - Addr: mustConfigResourceAddr("test_foo.bar"), - Config: rc, - }, - } - - { - var diags tfdiags.Diagnostics - diags = diags.Append(tfdiags.SimpleWarning("foo is deprecated")) - mp.ValidateProvisionerConfigResponse = provisioners.ValidateProvisionerConfigResponse{ - Diagnostics: diags, - } - } - - diags := node.validateProvisioner(ctx, pc) - if len(diags) != 1 { - t.Fatalf("wrong number of diagnostics in %s; want one warning", diags.ErrWithWarnings()) - } - - if got, want := diags[0].Description().Summary, mp.ValidateProvisionerConfigResponse.Diagnostics[0].Description().Summary; got != want { - t.Fatalf("wrong warning %q; want %q", got, want) - } -} - -func TestNodeValidatableResource_ValidateProvisioner__connectionInvalid(t *testing.T) { - ctx := &MockEvalContext{} - ctx.installSimpleEval() - mp := &MockProvisioner{} - ps := &configschema.Block{} - ctx.ProvisionerSchemaSchema = ps - ctx.ProvisionerProvisioner = mp - - pc := &configs.Provisioner{ - Type: "baz", - Config: hcl.EmptyBody(), - Connection: &configs.Connection{ - Config: configs.SynthBody("", map[string]cty.Value{ - "type": cty.StringVal("ssh"), - "bananananananana": cty.StringVal("foo"), - "bazaz": cty.StringVal("bar"), - }), - }, - } - - rc := &configs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_foo", - Name: "bar", - Config: configs.SynthBody("", map[string]cty.Value{}), - Managed: &configs.ManagedResource{}, - } - - node := NodeValidatableResource{ - NodeAbstractResource: &NodeAbstractResource{ - Addr: mustConfigResourceAddr("test_foo.bar"), - Config: rc, - }, - } - - diags := node.validateProvisioner(ctx, pc) - if !diags.HasErrors() { - t.Fatalf("node.Eval succeeded; want error") - } - if len(diags) != 3 { - t.Fatalf("wrong number of diagnostics; want two errors\n\n%s", diags.Err()) - } - - errStr := diags.Err().Error() - if !(strings.Contains(errStr, "bananananananana") && strings.Contains(errStr, "bazaz")) { - t.Fatalf("wrong errors %q; want something about each of our invalid connInfo keys", errStr) - } -} - -func TestNodeValidatableResource_ValidateResource_managedResource(t *testing.T) { - mp := simpleMockProvider() - mp.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse { - if got, want := req.TypeName, "test_object"; got != want { - t.Fatalf("wrong resource type\ngot: %#v\nwant: %#v", got, want) - } - if got, want := req.Config.GetAttr("test_string"), cty.StringVal("bar"); !got.RawEquals(want) { - t.Fatalf("wrong value for test_string\ngot: %#v\nwant: %#v", got, want) - } - if got, want := req.Config.GetAttr("test_number"), cty.NumberIntVal(2); !got.RawEquals(want) { - t.Fatalf("wrong value for test_number\ngot: %#v\nwant: %#v", got, want) - } - return providers.ValidateResourceConfigResponse{} - } - - p := providers.Interface(mp) - rc := &configs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_object", - Name: "foo", - Config: configs.SynthBody("", map[string]cty.Value{ - "test_string": cty.StringVal("bar"), - "test_number": cty.NumberIntVal(2).Mark(marks.Sensitive), - }), - } - node := NodeValidatableResource{ - NodeAbstractResource: &NodeAbstractResource{ - Addr: mustConfigResourceAddr("test_foo.bar"), - Config: rc, - ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - }, - } - - ctx := &MockEvalContext{} - ctx.installSimpleEval() - ctx.ProviderSchemaSchema = mp.ProviderSchema() - ctx.ProviderProvider = p - - err := node.validateResource(ctx) - if err != nil { - t.Fatalf("err: %s", err) - } - - if !mp.ValidateResourceConfigCalled { - t.Fatal("Expected ValidateResourceConfig to be called, but it was not!") - } -} - -func TestNodeValidatableResource_ValidateResource_managedResourceCount(t *testing.T) { - // Setup - mp := simpleMockProvider() - mp.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse { - if got, want := req.TypeName, "test_object"; got != want { - t.Fatalf("wrong resource type\ngot: %#v\nwant: %#v", got, want) - } - if got, want := req.Config.GetAttr("test_string"), cty.StringVal("bar"); !got.RawEquals(want) { - t.Fatalf("wrong value for test_string\ngot: %#v\nwant: %#v", got, want) - } - return providers.ValidateResourceConfigResponse{} - } - - p := providers.Interface(mp) - - ctx := &MockEvalContext{} - ctx.installSimpleEval() - ctx.ProviderSchemaSchema = mp.ProviderSchema() - ctx.ProviderProvider = p - - tests := []struct { - name string - count hcl.Expression - }{ - { - "simple count", - hcltest.MockExprLiteral(cty.NumberIntVal(2)), - }, - { - "marked count value", - hcltest.MockExprLiteral(cty.NumberIntVal(3).Mark("marked")), - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - rc := &configs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_object", - Name: "foo", - Count: test.count, - Config: configs.SynthBody("", map[string]cty.Value{ - "test_string": cty.StringVal("bar"), - }), - } - node := NodeValidatableResource{ - NodeAbstractResource: &NodeAbstractResource{ - Addr: mustConfigResourceAddr("test_foo.bar"), - Config: rc, - ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - }, - } - - diags := node.validateResource(ctx) - if diags.HasErrors() { - t.Fatalf("err: %s", diags.Err()) - } - - if !mp.ValidateResourceConfigCalled { - t.Fatal("Expected ValidateResourceConfig to be called, but it was not!") - } - }) - } -} - -func TestNodeValidatableResource_ValidateResource_dataSource(t *testing.T) { - mp := simpleMockProvider() - mp.ValidateDataResourceConfigFn = func(req providers.ValidateDataResourceConfigRequest) providers.ValidateDataResourceConfigResponse { - if got, want := req.TypeName, "test_object"; got != want { - t.Fatalf("wrong resource type\ngot: %#v\nwant: %#v", got, want) - } - if got, want := req.Config.GetAttr("test_string"), cty.StringVal("bar"); !got.RawEquals(want) { - t.Fatalf("wrong value for test_string\ngot: %#v\nwant: %#v", got, want) - } - if got, want := req.Config.GetAttr("test_number"), cty.NumberIntVal(2); !got.RawEquals(want) { - t.Fatalf("wrong value for test_number\ngot: %#v\nwant: %#v", got, want) - } - return providers.ValidateDataResourceConfigResponse{} - } - - p := providers.Interface(mp) - rc := &configs.Resource{ - Mode: addrs.DataResourceMode, - Type: "test_object", - Name: "foo", - Config: configs.SynthBody("", map[string]cty.Value{ - "test_string": cty.StringVal("bar"), - "test_number": cty.NumberIntVal(2).Mark(marks.Sensitive), - }), - } - - node := NodeValidatableResource{ - NodeAbstractResource: &NodeAbstractResource{ - Addr: mustConfigResourceAddr("test_foo.bar"), - Config: rc, - ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - }, - } - - ctx := &MockEvalContext{} - ctx.installSimpleEval() - ctx.ProviderSchemaSchema = mp.ProviderSchema() - ctx.ProviderProvider = p - - diags := node.validateResource(ctx) - if diags.HasErrors() { - t.Fatalf("err: %s", diags.Err()) - } - - if !mp.ValidateDataResourceConfigCalled { - t.Fatal("Expected ValidateDataSourceConfig to be called, but it was not!") - } -} - -func TestNodeValidatableResource_ValidateResource_valid(t *testing.T) { - mp := simpleMockProvider() - mp.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse { - return providers.ValidateResourceConfigResponse{} - } - - p := providers.Interface(mp) - rc := &configs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_object", - Name: "foo", - Config: configs.SynthBody("", map[string]cty.Value{}), - } - node := NodeValidatableResource{ - NodeAbstractResource: &NodeAbstractResource{ - Addr: mustConfigResourceAddr("test_object.foo"), - Config: rc, - ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - }, - } - - ctx := &MockEvalContext{} - ctx.installSimpleEval() - ctx.ProviderSchemaSchema = mp.ProviderSchema() - ctx.ProviderProvider = p - - diags := node.validateResource(ctx) - if diags.HasErrors() { - t.Fatalf("err: %s", diags.Err()) - } -} - -func TestNodeValidatableResource_ValidateResource_warningsAndErrorsPassedThrough(t *testing.T) { - mp := simpleMockProvider() - mp.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse { - var diags tfdiags.Diagnostics - diags = diags.Append(tfdiags.SimpleWarning("warn")) - diags = diags.Append(errors.New("err")) - return providers.ValidateResourceConfigResponse{ - Diagnostics: diags, - } - } - - p := providers.Interface(mp) - rc := &configs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_object", - Name: "foo", - Config: configs.SynthBody("", map[string]cty.Value{}), - } - node := NodeValidatableResource{ - NodeAbstractResource: &NodeAbstractResource{ - Addr: mustConfigResourceAddr("test_foo.bar"), - Config: rc, - ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - }, - } - - ctx := &MockEvalContext{} - ctx.installSimpleEval() - ctx.ProviderSchemaSchema = mp.ProviderSchema() - ctx.ProviderProvider = p - - diags := node.validateResource(ctx) - if !diags.HasErrors() { - t.Fatal("unexpected success; want error") - } - - bySeverity := map[tfdiags.Severity]tfdiags.Diagnostics{} - for _, diag := range diags { - bySeverity[diag.Severity()] = append(bySeverity[diag.Severity()], diag) - } - if len(bySeverity[tfdiags.Warning]) != 1 || bySeverity[tfdiags.Warning][0].Description().Summary != "warn" { - t.Errorf("Expected 1 warning 'warn', got: %s", bySeverity[tfdiags.Warning].ErrWithWarnings()) - } - if len(bySeverity[tfdiags.Error]) != 1 || bySeverity[tfdiags.Error][0].Description().Summary != "err" { - t.Errorf("Expected 1 error 'err', got: %s", bySeverity[tfdiags.Error].Err()) - } -} - -func TestNodeValidatableResource_ValidateResource_invalidDependsOn(t *testing.T) { - mp := simpleMockProvider() - mp.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse { - return providers.ValidateResourceConfigResponse{} - } - - // We'll check a _valid_ config first, to make sure we're not failing - // for some other reason, and then make it invalid. - p := providers.Interface(mp) - rc := &configs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_object", - Name: "foo", - Config: configs.SynthBody("", map[string]cty.Value{}), - DependsOn: []hcl.Traversal{ - // Depending on path.module is pointless, since it is immediately - // available, but we allow all of the referencable addrs here - // for consistency: referencing them is harmless, and avoids the - // need for us to document a different subset of addresses that - // are valid in depends_on. - // For the sake of this test, it's a valid address we can use that - // doesn't require something else to exist in the configuration. - { - hcl.TraverseRoot{ - Name: "path", - }, - hcl.TraverseAttr{ - Name: "module", - }, - }, - }, - } - node := NodeValidatableResource{ - NodeAbstractResource: &NodeAbstractResource{ - Addr: mustConfigResourceAddr("test_foo.bar"), - Config: rc, - ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - }, - } - - ctx := &MockEvalContext{} - ctx.installSimpleEval() - - ctx.ProviderSchemaSchema = mp.ProviderSchema() - ctx.ProviderProvider = p - - diags := node.validateResource(ctx) - if diags.HasErrors() { - t.Fatalf("error for supposedly-valid config: %s", diags.ErrWithWarnings()) - } - - // Now we'll make it invalid by adding additional traversal steps at - // the end of what we're referencing. This is intended to catch the - // situation where the user tries to depend on e.g. a specific resource - // attribute, rather than the whole resource, like aws_instance.foo.id. - rc.DependsOn = append(rc.DependsOn, hcl.Traversal{ - hcl.TraverseRoot{ - Name: "path", - }, - hcl.TraverseAttr{ - Name: "module", - }, - hcl.TraverseAttr{ - Name: "extra", - }, - }) - - diags = node.validateResource(ctx) - if !diags.HasErrors() { - t.Fatal("no error for invalid depends_on") - } - if got, want := diags.Err().Error(), "Invalid depends_on reference"; !strings.Contains(got, want) { - t.Fatalf("wrong error\ngot: %s\nwant: Message containing %q", got, want) - } - - // Test for handling an unknown root without attribute, like a - // typo that omits the dot inbetween "path.module". - rc.DependsOn = append(rc.DependsOn, hcl.Traversal{ - hcl.TraverseRoot{ - Name: "pathmodule", - }, - }) - - diags = node.validateResource(ctx) - if !diags.HasErrors() { - t.Fatal("no error for invalid depends_on") - } - if got, want := diags.Err().Error(), "Invalid depends_on reference"; !strings.Contains(got, want) { - t.Fatalf("wrong error\ngot: %s\nwant: Message containing %q", got, want) - } -} - -func TestNodeValidatableResource_ValidateResource_invalidIgnoreChangesNonexistent(t *testing.T) { - mp := simpleMockProvider() - mp.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse { - return providers.ValidateResourceConfigResponse{} - } - - // We'll check a _valid_ config first, to make sure we're not failing - // for some other reason, and then make it invalid. - p := providers.Interface(mp) - rc := &configs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_object", - Name: "foo", - Config: configs.SynthBody("", map[string]cty.Value{}), - Managed: &configs.ManagedResource{ - IgnoreChanges: []hcl.Traversal{ - { - hcl.TraverseAttr{ - Name: "test_string", - }, - }, - }, - }, - } - node := NodeValidatableResource{ - NodeAbstractResource: &NodeAbstractResource{ - Addr: mustConfigResourceAddr("test_foo.bar"), - Config: rc, - ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - }, - } - - ctx := &MockEvalContext{} - ctx.installSimpleEval() - - ctx.ProviderSchemaSchema = mp.ProviderSchema() - ctx.ProviderProvider = p - - diags := node.validateResource(ctx) - if diags.HasErrors() { - t.Fatalf("error for supposedly-valid config: %s", diags.ErrWithWarnings()) - } - - // Now we'll make it invalid by attempting to ignore a nonexistent - // attribute. - rc.Managed.IgnoreChanges = append(rc.Managed.IgnoreChanges, hcl.Traversal{ - hcl.TraverseAttr{ - Name: "nonexistent", - }, - }) - - diags = node.validateResource(ctx) - if !diags.HasErrors() { - t.Fatal("no error for invalid ignore_changes") - } - if got, want := diags.Err().Error(), "Unsupported attribute: This object has no argument, nested block, or exported attribute named \"nonexistent\""; !strings.Contains(got, want) { - t.Fatalf("wrong error\ngot: %s\nwant: Message containing %q", got, want) - } -} - -func TestNodeValidatableResource_ValidateResource_invalidIgnoreChangesComputed(t *testing.T) { - // construct a schema with a computed attribute - ms := &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "test_string": { - Type: cty.String, - Optional: true, - }, - "computed_string": { - Type: cty.String, - Computed: true, - Optional: false, - }, - }, - } - - mp := &MockProvider{ - GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{ - Provider: providers.Schema{Block: ms}, - ResourceTypes: map[string]providers.Schema{ - "test_object": providers.Schema{Block: ms}, - }, - }, - } - - mp.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse { - return providers.ValidateResourceConfigResponse{} - } - - // We'll check a _valid_ config first, to make sure we're not failing - // for some other reason, and then make it invalid. - p := providers.Interface(mp) - rc := &configs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_object", - Name: "foo", - Config: configs.SynthBody("", map[string]cty.Value{}), - Managed: &configs.ManagedResource{ - IgnoreChanges: []hcl.Traversal{ - { - hcl.TraverseAttr{ - Name: "test_string", - }, - }, - }, - }, - } - node := NodeValidatableResource{ - NodeAbstractResource: &NodeAbstractResource{ - Addr: mustConfigResourceAddr("test_foo.bar"), - Config: rc, - ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - }, - } - - ctx := &MockEvalContext{} - ctx.installSimpleEval() - - ctx.ProviderSchemaSchema = mp.ProviderSchema() - ctx.ProviderProvider = p - - diags := node.validateResource(ctx) - if diags.HasErrors() { - t.Fatalf("error for supposedly-valid config: %s", diags.ErrWithWarnings()) - } - - // Now we'll make it invalid by attempting to ignore a computed - // attribute. - rc.Managed.IgnoreChanges = append(rc.Managed.IgnoreChanges, hcl.Traversal{ - hcl.TraverseAttr{ - Name: "computed_string", - }, - }) - - diags = node.validateResource(ctx) - if diags.HasErrors() { - t.Fatalf("got unexpected error: %s", diags.ErrWithWarnings()) - } - if got, want := diags.ErrWithWarnings().Error(), `Redundant ignore_changes element: Adding an attribute name to ignore_changes tells Terraform to ignore future changes to the argument in configuration after the object has been created, retaining the value originally configured. - -The attribute computed_string is decided by the provider alone and therefore there can be no configured value to compare with. Including this attribute in ignore_changes has no effect. Remove the attribute from ignore_changes to quiet this warning.`; !strings.Contains(got, want) { - t.Fatalf("wrong error\ngot: %s\nwant: Message containing %q", got, want) - } -} diff --git a/internal/terraform/node_root_variable.go b/internal/terraform/node_root_variable.go deleted file mode 100644 index 33f439d7cd9a..000000000000 --- a/internal/terraform/node_root_variable.go +++ /dev/null @@ -1,115 +0,0 @@ -package terraform - -import ( - "log" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/dag" - "github.com/hashicorp/terraform/internal/tfdiags" - "github.com/zclconf/go-cty/cty" -) - -// NodeRootVariable represents a root variable input. -type NodeRootVariable struct { - Addr addrs.InputVariable - Config *configs.Variable - - // RawValue is the value for the variable set from outside Terraform - // Core, such as on the command line, or from an environment variable, - // or similar. This is the raw value that was provided, not yet - // converted or validated, and can be nil for a variable that isn't - // set at all. - RawValue *InputValue -} - -var ( - _ GraphNodeModuleInstance = (*NodeRootVariable)(nil) - _ GraphNodeReferenceable = (*NodeRootVariable)(nil) -) - -func (n *NodeRootVariable) Name() string { - return n.Addr.String() -} - -// GraphNodeModuleInstance -func (n *NodeRootVariable) Path() addrs.ModuleInstance { - return addrs.RootModuleInstance -} - -func (n *NodeRootVariable) ModulePath() addrs.Module { - return addrs.RootModule -} - -// GraphNodeReferenceable -func (n *NodeRootVariable) ReferenceableAddrs() []addrs.Referenceable { - return []addrs.Referenceable{n.Addr} -} - -// GraphNodeExecutable -func (n *NodeRootVariable) Execute(ctx EvalContext, op walkOperation) tfdiags.Diagnostics { - // Root module variables are special in that they are provided directly - // by the caller (usually, the CLI layer) and so we don't really need to - // evaluate them in the usual sense, but we do need to process the raw - // values given by the caller to match what the module is expecting, and - // make sure the values are valid. - var diags tfdiags.Diagnostics - - addr := addrs.RootModuleInstance.InputVariable(n.Addr.Name) - log.Printf("[TRACE] NodeRootVariable: evaluating %s", addr) - - if n.Config == nil { - // Because we build NodeRootVariable from configuration in the normal - // case it's strange to get here, but we tolerate it to allow for - // tests that might not populate the inputs fully. - return nil - } - - givenVal := n.RawValue - if givenVal == nil { - // We'll use cty.NilVal to represent the variable not being set at - // all, which for historical reasons is unfortunately different than - // explicitly setting it to null in some cases. In normal code we - // should never get here because all variables should have raw - // values, but we can get here in some historical tests that call - // in directly and don't necessarily obey the rules. - givenVal = &InputValue{ - Value: cty.NilVal, - SourceType: ValueFromUnknown, - } - } - - finalVal, moreDiags := prepareFinalInputVariableValue( - addr, - givenVal, - n.Config, - ) - diags = diags.Append(moreDiags) - if moreDiags.HasErrors() { - // No point in proceeding to validations then, because they'll - // probably fail trying to work with a value of the wrong type. - return diags - } - - ctx.SetRootModuleArgument(addr.Variable, finalVal) - - moreDiags = evalVariableValidations( - addrs.RootModuleInstance.InputVariable(n.Addr.Name), - n.Config, - nil, // not set for root module variables - ctx, - ) - diags = diags.Append(moreDiags) - return diags -} - -// dag.GraphNodeDotter impl. -func (n *NodeRootVariable) DotNode(name string, opts *dag.DotOpts) *dag.DotNode { - return &dag.DotNode{ - Name: name, - Attrs: map[string]string{ - "label": n.Name(), - "shape": "note", - }, - } -} diff --git a/internal/terraform/node_root_variable_test.go b/internal/terraform/node_root_variable_test.go deleted file mode 100644 index 537cecce9f7d..000000000000 --- a/internal/terraform/node_root_variable_test.go +++ /dev/null @@ -1,167 +0,0 @@ -package terraform - -import ( - "testing" - - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/hcl/v2/hcltest" - "github.com/zclconf/go-cty/cty" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/lang" -) - -func TestNodeRootVariableExecute(t *testing.T) { - t.Run("type conversion", func(t *testing.T) { - ctx := new(MockEvalContext) - - n := &NodeRootVariable{ - Addr: addrs.InputVariable{Name: "foo"}, - Config: &configs.Variable{ - Name: "foo", - Type: cty.String, - ConstraintType: cty.String, - }, - RawValue: &InputValue{ - Value: cty.True, - SourceType: ValueFromUnknown, - }, - } - - diags := n.Execute(ctx, walkApply) - if diags.HasErrors() { - t.Fatalf("unexpected error: %s", diags.Err()) - } - - if !ctx.SetRootModuleArgumentCalled { - t.Fatalf("ctx.SetRootModuleArgument wasn't called") - } - if got, want := ctx.SetRootModuleArgumentAddr.String(), "var.foo"; got != want { - t.Errorf("wrong address for ctx.SetRootModuleArgument\ngot: %s\nwant: %s", got, want) - } - if got, want := ctx.SetRootModuleArgumentValue, cty.StringVal("true"); !want.RawEquals(got) { - // NOTE: The given value was cty.Bool but the type constraint was - // cty.String, so it was NodeRootVariable's responsibility to convert - // as part of preparing the "final value". - t.Errorf("wrong value for ctx.SetRootModuleArgument\ngot: %#v\nwant: %#v", got, want) - } - }) - t.Run("validation", func(t *testing.T) { - ctx := new(MockEvalContext) - - // The variable validation function gets called with Terraform's - // built-in functions available, so we need a minimal scope just for - // it to get the functions from. - ctx.EvaluationScopeScope = &lang.Scope{} - - // We need to reimplement a _little_ bit of EvalContextBuiltin logic - // here to get a similar effect with EvalContextMock just to get the - // value to flow through here in a realistic way that'll make this test - // useful. - var finalVal cty.Value - ctx.SetRootModuleArgumentFunc = func(addr addrs.InputVariable, v cty.Value) { - if addr.Name == "foo" { - t.Logf("set %s to %#v", addr.String(), v) - finalVal = v - } - } - ctx.GetVariableValueFunc = func(addr addrs.AbsInputVariableInstance) cty.Value { - if addr.String() != "var.foo" { - return cty.NilVal - } - t.Logf("reading final val for %s (%#v)", addr.String(), finalVal) - return finalVal - } - - n := &NodeRootVariable{ - Addr: addrs.InputVariable{Name: "foo"}, - Config: &configs.Variable{ - Name: "foo", - Type: cty.Number, - ConstraintType: cty.Number, - Validations: []*configs.CheckRule{ - { - Condition: fakeHCLExpressionFunc(func(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { - // This returns true only if the given variable value - // is exactly cty.Number, which allows us to verify - // that we were given the value _after_ type - // conversion. - // This had previously not been handled correctly, - // as reported in: - // https://github.com/hashicorp/terraform/issues/29899 - vars := ctx.Variables["var"] - if vars == cty.NilVal || !vars.Type().IsObjectType() || !vars.Type().HasAttribute("foo") { - t.Logf("var.foo isn't available") - return cty.False, nil - } - val := vars.GetAttr("foo") - if val == cty.NilVal || val.Type() != cty.Number { - t.Logf("var.foo is %#v; want a number", val) - return cty.False, nil - } - return cty.True, nil - }), - ErrorMessage: hcltest.MockExprLiteral(cty.StringVal("Must be a number.")), - }, - }, - }, - RawValue: &InputValue{ - // Note: This is a string, but the variable's type constraint - // is number so it should be converted before use. - Value: cty.StringVal("5"), - SourceType: ValueFromUnknown, - }, - } - - diags := n.Execute(ctx, walkApply) - if diags.HasErrors() { - t.Fatalf("unexpected error: %s", diags.Err()) - } - - if !ctx.SetRootModuleArgumentCalled { - t.Fatalf("ctx.SetRootModuleArgument wasn't called") - } - if got, want := ctx.SetRootModuleArgumentAddr.String(), "var.foo"; got != want { - t.Errorf("wrong address for ctx.SetRootModuleArgument\ngot: %s\nwant: %s", got, want) - } - if got, want := ctx.SetRootModuleArgumentValue, cty.NumberIntVal(5); !want.RawEquals(got) { - // NOTE: The given value was cty.Bool but the type constraint was - // cty.String, so it was NodeRootVariable's responsibility to convert - // as part of preparing the "final value". - t.Errorf("wrong value for ctx.SetRootModuleArgument\ngot: %#v\nwant: %#v", got, want) - } - }) -} - -// fakeHCLExpressionFunc is a fake implementation of hcl.Expression that just -// directly produces a value with direct Go code. -// -// An expression of this type has no references and so it cannot access any -// variables from the EvalContext unless something else arranges for them -// to be guaranteed available. For example, custom variable validations just -// unconditionally have access to the variable they are validating regardless -// of references. -type fakeHCLExpressionFunc func(*hcl.EvalContext) (cty.Value, hcl.Diagnostics) - -var _ hcl.Expression = fakeHCLExpressionFunc(nil) - -func (f fakeHCLExpressionFunc) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { - return f(ctx) -} - -func (f fakeHCLExpressionFunc) Variables() []hcl.Traversal { - return nil -} - -func (f fakeHCLExpressionFunc) Range() hcl.Range { - return hcl.Range{ - Filename: "fake", - Start: hcl.InitialPos, - End: hcl.InitialPos, - } -} - -func (f fakeHCLExpressionFunc) StartRange() hcl.Range { - return f.Range() -} diff --git a/internal/terraform/node_value.go b/internal/terraform/node_value.go deleted file mode 100644 index 62a6e6ae8374..000000000000 --- a/internal/terraform/node_value.go +++ /dev/null @@ -1,10 +0,0 @@ -package terraform - -// graphNodeTemporaryValue is implemented by nodes that may represent temporary -// values, which are those not saved to the state file. This includes locals, -// variables, and non-root outputs. -// A boolean return value allows a node which may need to be saved to -// conditionally do so. -type graphNodeTemporaryValue interface { - temporaryValue() bool -} diff --git a/internal/terraform/phasestate_string.go b/internal/terraform/phasestate_string.go deleted file mode 100644 index 3c3b4f713af5..000000000000 --- a/internal/terraform/phasestate_string.go +++ /dev/null @@ -1,25 +0,0 @@ -// Code generated by "stringer -type phaseState"; DO NOT EDIT. - -package terraform - -import "strconv" - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[workingState-0] - _ = x[refreshState-1] - _ = x[prevRunState-2] -} - -const _phaseState_name = "workingStaterefreshStateprevRunState" - -var _phaseState_index = [...]uint8{0, 12, 24, 36} - -func (i phaseState) String() string { - if i < 0 || i >= phaseState(len(_phaseState_index)-1) { - return "phaseState(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _phaseState_name[_phaseState_index[i]:_phaseState_index[i+1]] -} diff --git a/internal/terraform/provider_mock.go b/internal/terraform/provider_mock.go deleted file mode 100644 index e10f8b98b75b..000000000000 --- a/internal/terraform/provider_mock.go +++ /dev/null @@ -1,539 +0,0 @@ -package terraform - -import ( - "fmt" - "sync" - - "github.com/zclconf/go-cty/cty" - ctyjson "github.com/zclconf/go-cty/cty/json" - "github.com/zclconf/go-cty/cty/msgpack" - - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/configs/hcl2shim" - "github.com/hashicorp/terraform/internal/providers" -) - -var _ providers.Interface = (*MockProvider)(nil) - -// MockProvider implements providers.Interface but mocks out all the -// calls for testing purposes. -type MockProvider struct { - sync.Mutex - - // Anything you want, in case you need to store extra data with the mock. - Meta interface{} - - GetProviderSchemaCalled bool - GetProviderSchemaResponse *providers.GetProviderSchemaResponse - - ValidateProviderConfigCalled bool - ValidateProviderConfigResponse *providers.ValidateProviderConfigResponse - ValidateProviderConfigRequest providers.ValidateProviderConfigRequest - ValidateProviderConfigFn func(providers.ValidateProviderConfigRequest) providers.ValidateProviderConfigResponse - - ValidateResourceConfigCalled bool - ValidateResourceConfigTypeName string - ValidateResourceConfigResponse *providers.ValidateResourceConfigResponse - ValidateResourceConfigRequest providers.ValidateResourceConfigRequest - ValidateResourceConfigFn func(providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse - - ValidateDataResourceConfigCalled bool - ValidateDataResourceConfigTypeName string - ValidateDataResourceConfigResponse *providers.ValidateDataResourceConfigResponse - ValidateDataResourceConfigRequest providers.ValidateDataResourceConfigRequest - ValidateDataResourceConfigFn func(providers.ValidateDataResourceConfigRequest) providers.ValidateDataResourceConfigResponse - - UpgradeResourceStateCalled bool - UpgradeResourceStateTypeName string - UpgradeResourceStateResponse *providers.UpgradeResourceStateResponse - UpgradeResourceStateRequest providers.UpgradeResourceStateRequest - UpgradeResourceStateFn func(providers.UpgradeResourceStateRequest) providers.UpgradeResourceStateResponse - - ConfigureProviderCalled bool - ConfigureProviderResponse *providers.ConfigureProviderResponse - ConfigureProviderRequest providers.ConfigureProviderRequest - ConfigureProviderFn func(providers.ConfigureProviderRequest) providers.ConfigureProviderResponse - - StopCalled bool - StopFn func() error - StopResponse error - - ReadResourceCalled bool - ReadResourceResponse *providers.ReadResourceResponse - ReadResourceRequest providers.ReadResourceRequest - ReadResourceFn func(providers.ReadResourceRequest) providers.ReadResourceResponse - - PlanResourceChangeCalled bool - PlanResourceChangeResponse *providers.PlanResourceChangeResponse - PlanResourceChangeRequest providers.PlanResourceChangeRequest - PlanResourceChangeFn func(providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse - - ApplyResourceChangeCalled bool - ApplyResourceChangeResponse *providers.ApplyResourceChangeResponse - ApplyResourceChangeRequest providers.ApplyResourceChangeRequest - ApplyResourceChangeFn func(providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse - - ImportResourceStateCalled bool - ImportResourceStateResponse *providers.ImportResourceStateResponse - ImportResourceStateRequest providers.ImportResourceStateRequest - ImportResourceStateFn func(providers.ImportResourceStateRequest) providers.ImportResourceStateResponse - - ReadDataSourceCalled bool - ReadDataSourceResponse *providers.ReadDataSourceResponse - ReadDataSourceRequest providers.ReadDataSourceRequest - ReadDataSourceFn func(providers.ReadDataSourceRequest) providers.ReadDataSourceResponse - - CloseCalled bool - CloseError error -} - -func (p *MockProvider) GetProviderSchema() providers.GetProviderSchemaResponse { - p.Lock() - defer p.Unlock() - p.GetProviderSchemaCalled = true - return p.getProviderSchema() -} - -func (p *MockProvider) getProviderSchema() providers.GetProviderSchemaResponse { - // This version of getProviderSchema doesn't do any locking, so it's suitable to - // call from other methods of this mock as long as they are already - // holding the lock. - if p.GetProviderSchemaResponse != nil { - return *p.GetProviderSchemaResponse - } - - return providers.GetProviderSchemaResponse{ - Provider: providers.Schema{}, - DataSources: map[string]providers.Schema{}, - ResourceTypes: map[string]providers.Schema{}, - } -} - -// ProviderSchema is a helper to convert from the internal GetProviderSchemaResponse to -// a ProviderSchema. -func (p *MockProvider) ProviderSchema() *ProviderSchema { - resp := p.getProviderSchema() - - schema := &ProviderSchema{ - Provider: resp.Provider.Block, - ProviderMeta: resp.ProviderMeta.Block, - ResourceTypes: map[string]*configschema.Block{}, - DataSources: map[string]*configschema.Block{}, - ResourceTypeSchemaVersions: map[string]uint64{}, - } - - for resType, s := range resp.ResourceTypes { - schema.ResourceTypes[resType] = s.Block - schema.ResourceTypeSchemaVersions[resType] = uint64(s.Version) - } - - for dataSource, s := range resp.DataSources { - schema.DataSources[dataSource] = s.Block - } - - return schema -} - -func (p *MockProvider) ValidateProviderConfig(r providers.ValidateProviderConfigRequest) (resp providers.ValidateProviderConfigResponse) { - p.Lock() - defer p.Unlock() - - p.ValidateProviderConfigCalled = true - p.ValidateProviderConfigRequest = r - if p.ValidateProviderConfigFn != nil { - return p.ValidateProviderConfigFn(r) - } - - if p.ValidateProviderConfigResponse != nil { - return *p.ValidateProviderConfigResponse - } - - resp.PreparedConfig = r.Config - return resp -} - -func (p *MockProvider) ValidateResourceConfig(r providers.ValidateResourceConfigRequest) (resp providers.ValidateResourceConfigResponse) { - p.Lock() - defer p.Unlock() - - p.ValidateResourceConfigCalled = true - p.ValidateResourceConfigRequest = r - - // Marshall the value to replicate behavior by the GRPC protocol, - // and return any relevant errors - resourceSchema, ok := p.getProviderSchema().ResourceTypes[r.TypeName] - if !ok { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("no schema found for %q", r.TypeName)) - return resp - } - - _, err := msgpack.Marshal(r.Config, resourceSchema.Block.ImpliedType()) - if err != nil { - resp.Diagnostics = resp.Diagnostics.Append(err) - return resp - } - - if p.ValidateResourceConfigFn != nil { - return p.ValidateResourceConfigFn(r) - } - - if p.ValidateResourceConfigResponse != nil { - return *p.ValidateResourceConfigResponse - } - - return resp -} - -func (p *MockProvider) ValidateDataResourceConfig(r providers.ValidateDataResourceConfigRequest) (resp providers.ValidateDataResourceConfigResponse) { - p.Lock() - defer p.Unlock() - - p.ValidateDataResourceConfigCalled = true - p.ValidateDataResourceConfigRequest = r - - // Marshall the value to replicate behavior by the GRPC protocol - dataSchema, ok := p.getProviderSchema().DataSources[r.TypeName] - if !ok { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("no schema found for %q", r.TypeName)) - return resp - } - _, err := msgpack.Marshal(r.Config, dataSchema.Block.ImpliedType()) - if err != nil { - resp.Diagnostics = resp.Diagnostics.Append(err) - return resp - } - - if p.ValidateDataResourceConfigFn != nil { - return p.ValidateDataResourceConfigFn(r) - } - - if p.ValidateDataResourceConfigResponse != nil { - return *p.ValidateDataResourceConfigResponse - } - - return resp -} - -func (p *MockProvider) UpgradeResourceState(r providers.UpgradeResourceStateRequest) (resp providers.UpgradeResourceStateResponse) { - p.Lock() - defer p.Unlock() - - if !p.ConfigureProviderCalled { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("Configure not called before UpgradeResourceState %q", r.TypeName)) - return resp - } - - schema, ok := p.getProviderSchema().ResourceTypes[r.TypeName] - if !ok { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("no schema found for %q", r.TypeName)) - return resp - } - - schemaType := schema.Block.ImpliedType() - - p.UpgradeResourceStateCalled = true - p.UpgradeResourceStateRequest = r - - if p.UpgradeResourceStateFn != nil { - return p.UpgradeResourceStateFn(r) - } - - if p.UpgradeResourceStateResponse != nil { - return *p.UpgradeResourceStateResponse - } - - switch { - case r.RawStateFlatmap != nil: - v, err := hcl2shim.HCL2ValueFromFlatmap(r.RawStateFlatmap, schemaType) - if err != nil { - resp.Diagnostics = resp.Diagnostics.Append(err) - return resp - } - resp.UpgradedState = v - case len(r.RawStateJSON) > 0: - v, err := ctyjson.Unmarshal(r.RawStateJSON, schemaType) - - if err != nil { - resp.Diagnostics = resp.Diagnostics.Append(err) - return resp - } - resp.UpgradedState = v - } - - return resp -} - -func (p *MockProvider) ConfigureProvider(r providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) { - p.Lock() - defer p.Unlock() - - p.ConfigureProviderCalled = true - p.ConfigureProviderRequest = r - - if p.ConfigureProviderFn != nil { - return p.ConfigureProviderFn(r) - } - - if p.ConfigureProviderResponse != nil { - return *p.ConfigureProviderResponse - } - - return resp -} - -func (p *MockProvider) Stop() error { - // We intentionally don't lock in this one because the whole point of this - // method is to be called concurrently with another operation that can - // be cancelled. The provider itself is responsible for handling - // any concurrency concerns in this case. - - p.StopCalled = true - if p.StopFn != nil { - return p.StopFn() - } - - return p.StopResponse -} - -func (p *MockProvider) ReadResource(r providers.ReadResourceRequest) (resp providers.ReadResourceResponse) { - p.Lock() - defer p.Unlock() - - p.ReadResourceCalled = true - p.ReadResourceRequest = r - - if !p.ConfigureProviderCalled { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("Configure not called before ReadResource %q", r.TypeName)) - return resp - } - - if p.ReadResourceFn != nil { - return p.ReadResourceFn(r) - } - - if p.ReadResourceResponse != nil { - resp = *p.ReadResourceResponse - - // Make sure the NewState conforms to the schema. - // This isn't always the case for the existing tests. - schema, ok := p.getProviderSchema().ResourceTypes[r.TypeName] - if !ok { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("no schema found for %q", r.TypeName)) - return resp - } - - newState, err := schema.Block.CoerceValue(resp.NewState) - if err != nil { - resp.Diagnostics = resp.Diagnostics.Append(err) - } - resp.NewState = newState - return resp - } - - // otherwise just return the same state we received - resp.NewState = r.PriorState - resp.Private = r.Private - return resp -} - -func (p *MockProvider) PlanResourceChange(r providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { - p.Lock() - defer p.Unlock() - - if !p.ConfigureProviderCalled { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("Configure not called before PlanResourceChange %q", r.TypeName)) - return resp - } - - p.PlanResourceChangeCalled = true - p.PlanResourceChangeRequest = r - - if p.PlanResourceChangeFn != nil { - return p.PlanResourceChangeFn(r) - } - - if p.PlanResourceChangeResponse != nil { - return *p.PlanResourceChangeResponse - } - - // this is a destroy plan, - if r.ProposedNewState.IsNull() { - resp.PlannedState = r.ProposedNewState - resp.PlannedPrivate = r.PriorPrivate - return resp - } - - schema, ok := p.getProviderSchema().ResourceTypes[r.TypeName] - if !ok { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("no schema found for %q", r.TypeName)) - return resp - } - - // The default plan behavior is to accept the proposed value, and mark all - // nil computed attributes as unknown. - val, err := cty.Transform(r.ProposedNewState, func(path cty.Path, v cty.Value) (cty.Value, error) { - // We're only concerned with known null values, which can be computed - // by the provider. - if !v.IsKnown() { - return v, nil - } - - attrSchema := schema.Block.AttributeByPath(path) - if attrSchema == nil { - // this is an intermediate path which does not represent an attribute - return v, nil - } - - // get the current configuration value, to detect when a - // computed+optional attributes has become unset - configVal, err := path.Apply(r.Config) - if err != nil { - return v, err - } - - switch { - case attrSchema.Computed && !attrSchema.Optional && v.IsNull(): - // this is the easy path, this value is not yet set, and _must_ be computed - return cty.UnknownVal(v.Type()), nil - - case attrSchema.Computed && attrSchema.Optional && !v.IsNull() && configVal.IsNull(): - // If an optional+computed value has gone from set to unset, it - // becomes computed. (this was not possible to do with legacy - // providers) - return cty.UnknownVal(v.Type()), nil - } - - return v, nil - }) - if err != nil { - resp.Diagnostics = resp.Diagnostics.Append(err) - return resp - } - - resp.PlannedPrivate = r.PriorPrivate - resp.PlannedState = val - - return resp -} - -func (p *MockProvider) ApplyResourceChange(r providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { - p.Lock() - p.ApplyResourceChangeCalled = true - p.ApplyResourceChangeRequest = r - p.Unlock() - - if !p.ConfigureProviderCalled { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("Configure not called before ApplyResourceChange %q", r.TypeName)) - return resp - } - - if p.ApplyResourceChangeFn != nil { - return p.ApplyResourceChangeFn(r) - } - - if p.ApplyResourceChangeResponse != nil { - return *p.ApplyResourceChangeResponse - } - - // if the value is nil, we return that directly to correspond to a delete - if r.PlannedState.IsNull() { - resp.NewState = r.PlannedState - return resp - } - - // the default behavior will be to create the minimal valid apply value by - // setting unknowns (which correspond to computed attributes) to a zero - // value. - val, _ := cty.Transform(r.PlannedState, func(path cty.Path, v cty.Value) (cty.Value, error) { - if !v.IsKnown() { - ty := v.Type() - switch { - case ty == cty.String: - return cty.StringVal(""), nil - case ty == cty.Number: - return cty.NumberIntVal(0), nil - case ty == cty.Bool: - return cty.False, nil - case ty.IsMapType(): - return cty.MapValEmpty(ty.ElementType()), nil - case ty.IsListType(): - return cty.ListValEmpty(ty.ElementType()), nil - default: - return cty.NullVal(ty), nil - } - } - return v, nil - }) - - resp.NewState = val - resp.Private = r.PlannedPrivate - - return resp -} - -func (p *MockProvider) ImportResourceState(r providers.ImportResourceStateRequest) (resp providers.ImportResourceStateResponse) { - p.Lock() - defer p.Unlock() - - if !p.ConfigureProviderCalled { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("Configure not called before ImportResourceState %q", r.TypeName)) - return resp - } - - p.ImportResourceStateCalled = true - p.ImportResourceStateRequest = r - if p.ImportResourceStateFn != nil { - return p.ImportResourceStateFn(r) - } - - if p.ImportResourceStateResponse != nil { - resp = *p.ImportResourceStateResponse - // fixup the cty value to match the schema - for i, res := range resp.ImportedResources { - schema, ok := p.getProviderSchema().ResourceTypes[res.TypeName] - if !ok { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("no schema found for %q", res.TypeName)) - return resp - } - - var err error - res.State, err = schema.Block.CoerceValue(res.State) - if err != nil { - resp.Diagnostics = resp.Diagnostics.Append(err) - return resp - } - - resp.ImportedResources[i] = res - } - } - - return resp -} - -func (p *MockProvider) ReadDataSource(r providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) { - p.Lock() - defer p.Unlock() - - if !p.ConfigureProviderCalled { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("Configure not called before ReadDataSource %q", r.TypeName)) - return resp - } - - p.ReadDataSourceCalled = true - p.ReadDataSourceRequest = r - - if p.ReadDataSourceFn != nil { - return p.ReadDataSourceFn(r) - } - - if p.ReadDataSourceResponse != nil { - resp = *p.ReadDataSourceResponse - } - - return resp -} - -func (p *MockProvider) Close() error { - p.CloseCalled = true - return p.CloseError -} diff --git a/internal/terraform/provisioner_mock.go b/internal/terraform/provisioner_mock.go deleted file mode 100644 index fe76157a2daf..000000000000 --- a/internal/terraform/provisioner_mock.go +++ /dev/null @@ -1,104 +0,0 @@ -package terraform - -import ( - "sync" - - "github.com/hashicorp/terraform/internal/provisioners" -) - -var _ provisioners.Interface = (*MockProvisioner)(nil) - -// MockProvisioner implements provisioners.Interface but mocks out all the -// calls for testing purposes. -type MockProvisioner struct { - sync.Mutex - // Anything you want, in case you need to store extra data with the mock. - Meta interface{} - - GetSchemaCalled bool - GetSchemaResponse provisioners.GetSchemaResponse - - ValidateProvisionerConfigCalled bool - ValidateProvisionerConfigRequest provisioners.ValidateProvisionerConfigRequest - ValidateProvisionerConfigResponse provisioners.ValidateProvisionerConfigResponse - ValidateProvisionerConfigFn func(provisioners.ValidateProvisionerConfigRequest) provisioners.ValidateProvisionerConfigResponse - - ProvisionResourceCalled bool - ProvisionResourceRequest provisioners.ProvisionResourceRequest - ProvisionResourceResponse provisioners.ProvisionResourceResponse - ProvisionResourceFn func(provisioners.ProvisionResourceRequest) provisioners.ProvisionResourceResponse - - StopCalled bool - StopResponse error - StopFn func() error - - CloseCalled bool - CloseResponse error - CloseFn func() error -} - -func (p *MockProvisioner) GetSchema() provisioners.GetSchemaResponse { - p.Lock() - defer p.Unlock() - - p.GetSchemaCalled = true - return p.getSchema() -} - -// getSchema is the implementation of GetSchema, which can be called from other -// methods on MockProvisioner that may already be holding the lock. -func (p *MockProvisioner) getSchema() provisioners.GetSchemaResponse { - return p.GetSchemaResponse -} - -func (p *MockProvisioner) ValidateProvisionerConfig(r provisioners.ValidateProvisionerConfigRequest) provisioners.ValidateProvisionerConfigResponse { - p.Lock() - defer p.Unlock() - - p.ValidateProvisionerConfigCalled = true - p.ValidateProvisionerConfigRequest = r - if p.ValidateProvisionerConfigFn != nil { - return p.ValidateProvisionerConfigFn(r) - } - return p.ValidateProvisionerConfigResponse -} - -func (p *MockProvisioner) ProvisionResource(r provisioners.ProvisionResourceRequest) provisioners.ProvisionResourceResponse { - p.Lock() - defer p.Unlock() - - p.ProvisionResourceCalled = true - p.ProvisionResourceRequest = r - if p.ProvisionResourceFn != nil { - fn := p.ProvisionResourceFn - return fn(r) - } - - return p.ProvisionResourceResponse -} - -func (p *MockProvisioner) Stop() error { - // We intentionally don't lock in this one because the whole point of this - // method is to be called concurrently with another operation that can - // be cancelled. The provisioner itself is responsible for handling - // any concurrency concerns in this case. - - p.StopCalled = true - if p.StopFn != nil { - return p.StopFn() - } - - return p.StopResponse -} - -func (p *MockProvisioner) Close() error { - p.Lock() - defer p.Unlock() - - p.CloseCalled = true - if p.CloseFn != nil { - return p.CloseFn() - } - - return p.CloseResponse -} diff --git a/internal/terraform/provisioner_mock_test.go b/internal/terraform/provisioner_mock_test.go deleted file mode 100644 index a9d9d7bf3dcd..000000000000 --- a/internal/terraform/provisioner_mock_test.go +++ /dev/null @@ -1,27 +0,0 @@ -package terraform - -import ( - "github.com/hashicorp/terraform/internal/provisioners" -) - -// simpleMockProvisioner returns a MockProvisioner that is pre-configured -// with schema for its own config, with the same content as returned by -// function simpleTestSchema. -// -// For most reasonable uses the returned provisioner must be registered in a -// componentFactory under the name "test". Use simpleMockComponentFactory -// to obtain a pre-configured componentFactory containing the result of -// this function along with simpleMockProvider, both registered as "test". -// -// The returned provisioner has no other behaviors by default, but the caller -// may modify it in order to stub any other required functionality, or modify -// the default schema stored in the field GetSchemaReturn. Each new call to -// simpleTestProvisioner produces entirely new instances of all of the nested -// objects so that callers can mutate without affecting mock objects. -func simpleMockProvisioner() *MockProvisioner { - return &MockProvisioner{ - GetSchemaResponse: provisioners.GetSchemaResponse{ - Provisioner: simpleTestSchema(), - }, - } -} diff --git a/internal/terraform/reduce_plan.go b/internal/terraform/reduce_plan.go deleted file mode 100644 index 17a58eff5c13..000000000000 --- a/internal/terraform/reduce_plan.go +++ /dev/null @@ -1,32 +0,0 @@ -package terraform - -import ( - "log" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/plans" -) - -// reducePlan takes a planned resource instance change as might be produced by -// Plan or PlanDestroy and "simplifies" it to a single atomic action to be -// performed by a specific graph node. -// -// Callers must specify whether they are a destroy node or a regular apply node. -// If the result is NoOp then the given change requires no action for the -// specific graph node calling this and so evaluation of the that graph node -// should exit early and take no action. -// -// The returned object may either be identical to the input change or a new -// change object derived from the input. Because of the former case, the caller -// must not mutate the object returned in OutChange. -func reducePlan(addr addrs.ResourceInstance, in *plans.ResourceInstanceChange, destroy bool) *plans.ResourceInstanceChange { - out := in.Simplify(destroy) - if out.Action != in.Action { - if destroy { - log.Printf("[TRACE] reducePlan: %s change simplified from %s to %s for destroy node", addr, in.Action, out.Action) - } else { - log.Printf("[TRACE] reducePlan: %s change simplified from %s to %s for apply node", addr, in.Action, out.Action) - } - } - return out -} diff --git a/internal/terraform/reduce_plan_test.go b/internal/terraform/reduce_plan_test.go deleted file mode 100644 index f32101aaf582..000000000000 --- a/internal/terraform/reduce_plan_test.go +++ /dev/null @@ -1,443 +0,0 @@ -package terraform - -import ( - "testing" - - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/zclconf/go-cty/cty" -) - -func TestProcessIgnoreChangesIndividual(t *testing.T) { - tests := map[string]struct { - Old, New cty.Value - Ignore []string - Want cty.Value - }{ - "string": { - cty.ObjectVal(map[string]cty.Value{ - "a": cty.StringVal("a value"), - "b": cty.StringVal("b value"), - }), - cty.ObjectVal(map[string]cty.Value{ - "a": cty.StringVal("new a value"), - "b": cty.StringVal("new b value"), - }), - []string{"a"}, - cty.ObjectVal(map[string]cty.Value{ - "a": cty.StringVal("a value"), - "b": cty.StringVal("new b value"), - }), - }, - "changed type": { - cty.ObjectVal(map[string]cty.Value{ - "a": cty.StringVal("a value"), - "b": cty.StringVal("b value"), - }), - cty.ObjectVal(map[string]cty.Value{ - "a": cty.NumberIntVal(1), - "b": cty.StringVal("new b value"), - }), - []string{"a"}, - cty.ObjectVal(map[string]cty.Value{ - "a": cty.StringVal("a value"), - "b": cty.StringVal("new b value"), - }), - }, - "list": { - cty.ObjectVal(map[string]cty.Value{ - "a": cty.ListVal([]cty.Value{ - cty.StringVal("a0 value"), - cty.StringVal("a1 value"), - }), - "b": cty.StringVal("b value"), - }), - cty.ObjectVal(map[string]cty.Value{ - "a": cty.ListVal([]cty.Value{ - cty.StringVal("new a0 value"), - cty.StringVal("new a1 value"), - }), - "b": cty.StringVal("new b value"), - }), - []string{"a"}, - cty.ObjectVal(map[string]cty.Value{ - "a": cty.ListVal([]cty.Value{ - cty.StringVal("a0 value"), - cty.StringVal("a1 value"), - }), - "b": cty.StringVal("new b value"), - }), - }, - "list_index": { - cty.ObjectVal(map[string]cty.Value{ - "a": cty.ListVal([]cty.Value{ - cty.StringVal("a0 value"), - cty.StringVal("a1 value"), - }), - "b": cty.StringVal("b value"), - }), - cty.ObjectVal(map[string]cty.Value{ - "a": cty.ListVal([]cty.Value{ - cty.StringVal("new a0 value"), - cty.StringVal("new a1 value"), - }), - "b": cty.StringVal("new b value"), - }), - []string{"a[1]"}, - cty.ObjectVal(map[string]cty.Value{ - "a": cty.ListVal([]cty.Value{ - cty.StringVal("new a0 value"), - cty.StringVal("a1 value"), - }), - "b": cty.StringVal("new b value"), - }), - }, - "map": { - cty.ObjectVal(map[string]cty.Value{ - "a": cty.MapVal(map[string]cty.Value{ - "a0": cty.StringVal("a0 value"), - "a1": cty.StringVal("a1 value"), - }), - "b": cty.StringVal("b value"), - }), - cty.ObjectVal(map[string]cty.Value{ - "a": cty.MapVal(map[string]cty.Value{ - "a0": cty.StringVal("new a0 value"), - "a1": cty.UnknownVal(cty.String), - }), - "b": cty.StringVal("b value"), - }), - []string{`a`}, - cty.ObjectVal(map[string]cty.Value{ - "a": cty.MapVal(map[string]cty.Value{ - "a0": cty.StringVal("a0 value"), - "a1": cty.StringVal("a1 value"), - }), - "b": cty.StringVal("b value"), - }), - }, - "map_index": { - cty.ObjectVal(map[string]cty.Value{ - "a": cty.MapVal(map[string]cty.Value{ - "a0": cty.StringVal("a0 value"), - "a1": cty.StringVal("a1 value"), - }), - "b": cty.StringVal("b value"), - }), - cty.ObjectVal(map[string]cty.Value{ - "a": cty.MapVal(map[string]cty.Value{ - "a0": cty.StringVal("new a0 value"), - "a1": cty.StringVal("new a1 value"), - }), - "b": cty.StringVal("b value"), - }), - []string{`a["a1"]`}, - cty.ObjectVal(map[string]cty.Value{ - "a": cty.MapVal(map[string]cty.Value{ - "a0": cty.StringVal("new a0 value"), - "a1": cty.StringVal("a1 value"), - }), - "b": cty.StringVal("b value"), - }), - }, - "map_index_no_config": { - cty.ObjectVal(map[string]cty.Value{ - "a": cty.MapVal(map[string]cty.Value{ - "a0": cty.StringVal("a0 value"), - "a1": cty.StringVal("a1 value"), - }), - "b": cty.StringVal("b value"), - }), - cty.ObjectVal(map[string]cty.Value{ - "a": cty.NullVal(cty.Map(cty.String)), - "b": cty.StringVal("b value"), - }), - []string{`a["a1"]`}, - cty.ObjectVal(map[string]cty.Value{ - "a": cty.MapVal(map[string]cty.Value{ - "a1": cty.StringVal("a1 value"), - }), - "b": cty.StringVal("b value"), - }), - }, - "map_index_unknown_value": { - cty.ObjectVal(map[string]cty.Value{ - "a": cty.MapVal(map[string]cty.Value{ - "a0": cty.StringVal("a0 value"), - "a1": cty.StringVal("a1 value"), - }), - "b": cty.StringVal("b value"), - }), - cty.ObjectVal(map[string]cty.Value{ - "a": cty.MapVal(map[string]cty.Value{ - "a0": cty.StringVal("a0 value"), - "a1": cty.UnknownVal(cty.String), - }), - "b": cty.StringVal("b value"), - }), - []string{`a["a1"]`}, - cty.ObjectVal(map[string]cty.Value{ - "a": cty.MapVal(map[string]cty.Value{ - "a0": cty.StringVal("a0 value"), - "a1": cty.StringVal("a1 value"), - }), - "b": cty.StringVal("b value"), - }), - }, - "map_index_multiple_keys": { - cty.ObjectVal(map[string]cty.Value{ - "a": cty.MapVal(map[string]cty.Value{ - "a0": cty.StringVal("a0 value"), - "a1": cty.StringVal("a1 value"), - "a2": cty.StringVal("a2 value"), - "a3": cty.StringVal("a3 value"), - }), - "b": cty.StringVal("b value"), - }), - cty.ObjectVal(map[string]cty.Value{ - "a": cty.NullVal(cty.Map(cty.String)), - "b": cty.StringVal("new b value"), - }), - []string{`a["a1"]`, `a["a2"]`, `a["a3"]`, `b`}, - cty.ObjectVal(map[string]cty.Value{ - "a": cty.MapVal(map[string]cty.Value{ - "a1": cty.StringVal("a1 value"), - "a2": cty.StringVal("a2 value"), - "a3": cty.StringVal("a3 value"), - }), - "b": cty.StringVal("b value"), - }), - }, - "map_index_redundant": { - cty.ObjectVal(map[string]cty.Value{ - "a": cty.MapVal(map[string]cty.Value{ - "a0": cty.StringVal("a0 value"), - "a1": cty.StringVal("a1 value"), - "a2": cty.StringVal("a2 value"), - }), - "b": cty.StringVal("b value"), - }), - cty.ObjectVal(map[string]cty.Value{ - "a": cty.NullVal(cty.Map(cty.String)), - "b": cty.StringVal("new b value"), - }), - []string{`a["a1"]`, `a`, `b`}, - cty.ObjectVal(map[string]cty.Value{ - "a": cty.MapVal(map[string]cty.Value{ - "a0": cty.StringVal("a0 value"), - "a1": cty.StringVal("a1 value"), - "a2": cty.StringVal("a2 value"), - }), - "b": cty.StringVal("b value"), - }), - }, - "missing_map_index": { - cty.ObjectVal(map[string]cty.Value{ - "a": cty.MapVal(map[string]cty.Value{ - "a0": cty.StringVal("a0 value"), - "a1": cty.StringVal("a1 value"), - }), - "b": cty.StringVal("b value"), - }), - cty.ObjectVal(map[string]cty.Value{ - "a": cty.MapValEmpty(cty.String), - "b": cty.StringVal("b value"), - }), - []string{`a["a1"]`}, - cty.ObjectVal(map[string]cty.Value{ - "a": cty.MapVal(map[string]cty.Value{ - "a1": cty.StringVal("a1 value"), - }), - "b": cty.StringVal("b value"), - }), - }, - "missing_map_index_empty": { - cty.ObjectVal(map[string]cty.Value{ - "a": cty.MapValEmpty(cty.String), - }), - cty.ObjectVal(map[string]cty.Value{ - "a": cty.MapVal(map[string]cty.Value{ - "a": cty.StringVal("a0 value"), - }), - }), - []string{`a["a"]`}, - cty.ObjectVal(map[string]cty.Value{ - "a": cty.MapValEmpty(cty.String), - }), - }, - "missing_map_index_to_object": { - cty.ObjectVal(map[string]cty.Value{ - "a": cty.MapVal(map[string]cty.Value{ - "a": cty.ObjectVal(map[string]cty.Value{ - "a": cty.StringVal("aa0"), - "b": cty.StringVal("ab0"), - }), - "b": cty.ObjectVal(map[string]cty.Value{ - "a": cty.StringVal("ba0"), - "b": cty.StringVal("bb0"), - }), - }), - }), - cty.ObjectVal(map[string]cty.Value{ - "a": cty.MapValEmpty( - cty.Object(map[string]cty.Type{ - "a": cty.String, - "b": cty.String, - }), - ), - }), - // we expect the config to be used here, as the ignore changes was - // `a["a"].b`, but the change was larger than that removing - // `a["a"]` entirely. - []string{`a["a"].b`}, - cty.ObjectVal(map[string]cty.Value{ - "a": cty.MapValEmpty( - cty.Object(map[string]cty.Type{ - "a": cty.String, - "b": cty.String, - }), - ), - }), - }, - "missing_prior_map_index": { - cty.ObjectVal(map[string]cty.Value{ - "a": cty.MapVal(map[string]cty.Value{ - "a0": cty.StringVal("a0 value"), - }), - "b": cty.StringVal("b value"), - }), - cty.ObjectVal(map[string]cty.Value{ - "a": cty.MapVal(map[string]cty.Value{ - "a0": cty.StringVal("a0 value"), - "a1": cty.StringVal("new a1 value"), - }), - "b": cty.StringVal("b value"), - }), - []string{`a["a1"]`}, - cty.ObjectVal(map[string]cty.Value{ - "a": cty.MapVal(map[string]cty.Value{ - "a0": cty.StringVal("a0 value"), - }), - "b": cty.StringVal("b value"), - }), - }, - "object attribute": { - cty.ObjectVal(map[string]cty.Value{ - "a": cty.ObjectVal(map[string]cty.Value{ - "foo": cty.StringVal("a.foo value"), - "bar": cty.StringVal("a.bar value"), - }), - "b": cty.StringVal("b value"), - }), - cty.ObjectVal(map[string]cty.Value{ - "a": cty.ObjectVal(map[string]cty.Value{ - "foo": cty.StringVal("new a.foo value"), - "bar": cty.StringVal("new a.bar value"), - }), - "b": cty.StringVal("new b value"), - }), - []string{"a.bar"}, - cty.ObjectVal(map[string]cty.Value{ - "a": cty.ObjectVal(map[string]cty.Value{ - "foo": cty.StringVal("new a.foo value"), - "bar": cty.StringVal("a.bar value"), - }), - "b": cty.StringVal("new b value"), - }), - }, - "unknown_object_attribute": { - cty.ObjectVal(map[string]cty.Value{ - "a": cty.ObjectVal(map[string]cty.Value{ - "foo": cty.StringVal("a.foo value"), - "bar": cty.StringVal("a.bar value"), - }), - "b": cty.StringVal("b value"), - }), - cty.ObjectVal(map[string]cty.Value{ - "a": cty.ObjectVal(map[string]cty.Value{ - "foo": cty.StringVal("new a.foo value"), - "bar": cty.UnknownVal(cty.String), - }), - "b": cty.StringVal("new b value"), - }), - []string{"a.bar"}, - cty.ObjectVal(map[string]cty.Value{ - "a": cty.ObjectVal(map[string]cty.Value{ - "foo": cty.StringVal("new a.foo value"), - "bar": cty.StringVal("a.bar value"), - }), - "b": cty.StringVal("new b value"), - }), - }, - "null_map": { - cty.ObjectVal(map[string]cty.Value{ - "a": cty.StringVal("ok"), - "list": cty.ListVal([]cty.Value{ - cty.ObjectVal(map[string]cty.Value{ - "s": cty.StringVal("ok"), - "map": cty.NullVal(cty.Map(cty.String)), - }), - }), - }), - cty.ObjectVal(map[string]cty.Value{ - "a": cty.NullVal(cty.String), - "list": cty.ListVal([]cty.Value{ - cty.ObjectVal(map[string]cty.Value{ - "s": cty.StringVal("ok"), - "map": cty.NullVal(cty.Map(cty.String)), - }), - }), - }), - []string{"a"}, - cty.ObjectVal(map[string]cty.Value{ - "a": cty.StringVal("ok"), - "list": cty.ListVal([]cty.Value{ - cty.ObjectVal(map[string]cty.Value{ - "s": cty.StringVal("ok"), - "map": cty.NullVal(cty.Map(cty.String)), - }), - }), - }), - }, - "marked_map": { - cty.ObjectVal(map[string]cty.Value{ - "map": cty.MapVal(map[string]cty.Value{ - "key": cty.StringVal("val"), - }).Mark("marked"), - }), - cty.ObjectVal(map[string]cty.Value{ - "map": cty.MapVal(map[string]cty.Value{ - "key": cty.StringVal("new val"), - }).Mark("marked"), - }), - []string{`map["key"]`}, - cty.ObjectVal(map[string]cty.Value{ - "map": cty.MapVal(map[string]cty.Value{ - "key": cty.StringVal("val"), - }).Mark("marked"), - }), - }, - } - - for name, test := range tests { - t.Run(name, func(t *testing.T) { - ignore := make([]hcl.Traversal, len(test.Ignore)) - for i, ignoreStr := range test.Ignore { - trav, diags := hclsyntax.ParseTraversalAbs([]byte(ignoreStr), "", hcl.Pos{Line: 1, Column: 1}) - if diags.HasErrors() { - t.Fatalf("failed to parse %q: %s", ignoreStr, diags.Error()) - } - ignore[i] = trav - } - - ret, diags := processIgnoreChangesIndividual(test.Old, test.New, traversalsToPaths(ignore)) - if diags.HasErrors() { - t.Fatal(diags.Err()) - } - - if got, want := ret, test.Want; !want.RawEquals(got) { - t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, want) - } - }) - } -} diff --git a/internal/terraform/resource_provider_mock_test.go b/internal/terraform/resource_provider_mock_test.go deleted file mode 100644 index 6592b0a96011..000000000000 --- a/internal/terraform/resource_provider_mock_test.go +++ /dev/null @@ -1,102 +0,0 @@ -package terraform - -import ( - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/providers" - "github.com/zclconf/go-cty/cty" -) - -// mockProviderWithConfigSchema is a test helper to concisely create a mock -// provider with the given schema for its own configuration. -func mockProviderWithConfigSchema(schema *configschema.Block) *MockProvider { - return &MockProvider{ - GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{ - Provider: providers.Schema{Block: schema}, - }, - } -} - -// mockProviderWithResourceTypeSchema is a test helper to concisely create a mock -// provider with a schema containing a single resource type. -func mockProviderWithResourceTypeSchema(name string, schema *configschema.Block) *MockProvider { - return &MockProvider{ - GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{ - Provider: providers.Schema{ - Block: &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "string": { - Type: cty.String, - Optional: true, - }, - "list": { - Type: cty.List(cty.String), - Optional: true, - }, - "root": { - Type: cty.Map(cty.String), - Optional: true, - }, - }, - }, - }, - ResourceTypes: map[string]providers.Schema{ - name: providers.Schema{Block: schema}, - }, - }, - } -} - -// getProviderSchemaResponseFromProviderSchema is a test helper to convert a -// ProviderSchema to a GetProviderSchemaResponse for use when building a mock provider. -func getProviderSchemaResponseFromProviderSchema(providerSchema *ProviderSchema) *providers.GetProviderSchemaResponse { - resp := &providers.GetProviderSchemaResponse{ - Provider: providers.Schema{Block: providerSchema.Provider}, - ProviderMeta: providers.Schema{Block: providerSchema.ProviderMeta}, - ResourceTypes: map[string]providers.Schema{}, - DataSources: map[string]providers.Schema{}, - } - - for name, schema := range providerSchema.ResourceTypes { - resp.ResourceTypes[name] = providers.Schema{ - Block: schema, - Version: int64(providerSchema.ResourceTypeSchemaVersions[name]), - } - } - - for name, schema := range providerSchema.DataSources { - resp.DataSources[name] = providers.Schema{Block: schema} - } - - return resp -} - -// simpleMockProvider returns a MockProvider that is pre-configured -// with schema for its own config, for a resource type called "test_object" and -// for a data source also called "test_object". -// -// All three schemas have the same content as returned by function -// simpleTestSchema. -// -// For most reasonable uses the returned provider must be registered in a -// componentFactory under the name "test". Use simpleMockComponentFactory -// to obtain a pre-configured componentFactory containing the result of -// this function along with simpleMockProvisioner, both registered as "test". -// -// The returned provider has no other behaviors by default, but the caller may -// modify it in order to stub any other required functionality, or modify -// the default schema stored in the field GetSchemaReturn. Each new call to -// simpleTestProvider produces entirely new instances of all of the nested -// objects so that callers can mutate without affecting mock objects. -func simpleMockProvider() *MockProvider { - return &MockProvider{ - GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{ - Provider: providers.Schema{Block: simpleTestSchema()}, - ResourceTypes: map[string]providers.Schema{ - "test_object": providers.Schema{Block: simpleTestSchema()}, - }, - DataSources: map[string]providers.Schema{ - "test_object": providers.Schema{Block: simpleTestSchema()}, - }, - }, - } -} diff --git a/internal/terraform/schemas.go b/internal/terraform/schemas.go deleted file mode 100644 index 24edeb85aaf9..000000000000 --- a/internal/terraform/schemas.go +++ /dev/null @@ -1,187 +0,0 @@ -package terraform - -import ( - "fmt" - "log" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -// ProviderSchema is an alias for providers.Schemas, which is the new location -// for what we originally called terraform.ProviderSchema but which has -// moved out as part of ongoing refactoring to shrink down the main "terraform" -// package. -type ProviderSchema = providers.Schemas - -// Schemas is a container for various kinds of schema that Terraform needs -// during processing. -type Schemas struct { - Providers map[addrs.Provider]*providers.Schemas - Provisioners map[string]*configschema.Block -} - -// ProviderSchema returns the entire ProviderSchema object that was produced -// by the plugin for the given provider, or nil if no such schema is available. -// -// It's usually better to go use the more precise methods offered by type -// Schemas to handle this detail automatically. -func (ss *Schemas) ProviderSchema(provider addrs.Provider) *providers.Schemas { - if ss.Providers == nil { - return nil - } - return ss.Providers[provider] -} - -// ProviderConfig returns the schema for the provider configuration of the -// given provider type, or nil if no such schema is available. -func (ss *Schemas) ProviderConfig(provider addrs.Provider) *configschema.Block { - ps := ss.ProviderSchema(provider) - if ps == nil { - return nil - } - return ps.Provider -} - -// ResourceTypeConfig returns the schema for the configuration of a given -// resource type belonging to a given provider type, or nil of no such -// schema is available. -// -// In many cases the provider type is inferrable from the resource type name, -// but this is not always true because users can override the provider for -// a resource using the "provider" meta-argument. Therefore it's important to -// always pass the correct provider name, even though it many cases it feels -// redundant. -func (ss *Schemas) ResourceTypeConfig(provider addrs.Provider, resourceMode addrs.ResourceMode, resourceType string) (block *configschema.Block, schemaVersion uint64) { - ps := ss.ProviderSchema(provider) - if ps == nil || ps.ResourceTypes == nil { - return nil, 0 - } - return ps.SchemaForResourceType(resourceMode, resourceType) -} - -// ProvisionerConfig returns the schema for the configuration of a given -// provisioner, or nil of no such schema is available. -func (ss *Schemas) ProvisionerConfig(name string) *configschema.Block { - return ss.Provisioners[name] -} - -// loadSchemas searches the given configuration, state and plan (any of which -// may be nil) for constructs that have an associated schema, requests the -// necessary schemas from the given component factory (which must _not_ be nil), -// and returns a single object representing all of the necessary schemas. -// -// If an error is returned, it may be a wrapped tfdiags.Diagnostics describing -// errors across multiple separate objects. Errors here will usually indicate -// either misbehavior on the part of one of the providers or of the provider -// protocol itself. When returned with errors, the returned schemas object is -// still valid but may be incomplete. -func loadSchemas(config *configs.Config, state *states.State, plugins *contextPlugins) (*Schemas, error) { - schemas := &Schemas{ - Providers: map[addrs.Provider]*providers.Schemas{}, - Provisioners: map[string]*configschema.Block{}, - } - var diags tfdiags.Diagnostics - - newDiags := loadProviderSchemas(schemas.Providers, config, state, plugins) - diags = diags.Append(newDiags) - newDiags = loadProvisionerSchemas(schemas.Provisioners, config, plugins) - diags = diags.Append(newDiags) - - return schemas, diags.Err() -} - -func loadProviderSchemas(schemas map[addrs.Provider]*providers.Schemas, config *configs.Config, state *states.State, plugins *contextPlugins) tfdiags.Diagnostics { - var diags tfdiags.Diagnostics - - ensure := func(fqn addrs.Provider) { - name := fqn.String() - - if _, exists := schemas[fqn]; exists { - return - } - - log.Printf("[TRACE] LoadSchemas: retrieving schema for provider type %q", name) - schema, err := plugins.ProviderSchema(fqn) - if err != nil { - // We'll put a stub in the map so we won't re-attempt this on - // future calls, which would then repeat the same error message - // multiple times. - schemas[fqn] = &providers.Schemas{} - diags = diags.Append( - tfdiags.Sourceless( - tfdiags.Error, - "Failed to obtain provider schema", - fmt.Sprintf("Could not load the schema for provider %s: %s.", fqn, err), - ), - ) - return - } - - schemas[fqn] = schema - } - - if config != nil { - for _, fqn := range config.ProviderTypes() { - ensure(fqn) - } - } - - if state != nil { - needed := providers.AddressedTypesAbs(state.ProviderAddrs()) - for _, typeAddr := range needed { - ensure(typeAddr) - } - } - - return diags -} - -func loadProvisionerSchemas(schemas map[string]*configschema.Block, config *configs.Config, plugins *contextPlugins) tfdiags.Diagnostics { - var diags tfdiags.Diagnostics - - ensure := func(name string) { - if _, exists := schemas[name]; exists { - return - } - - log.Printf("[TRACE] LoadSchemas: retrieving schema for provisioner %q", name) - schema, err := plugins.ProvisionerSchema(name) - if err != nil { - // We'll put a stub in the map so we won't re-attempt this on - // future calls, which would then repeat the same error message - // multiple times. - schemas[name] = &configschema.Block{} - diags = diags.Append( - tfdiags.Sourceless( - tfdiags.Error, - "Failed to obtain provisioner schema", - fmt.Sprintf("Could not load the schema for provisioner %q: %s.", name, err), - ), - ) - return - } - - schemas[name] = schema - } - - if config != nil { - for _, rc := range config.Module.ManagedResources { - for _, pc := range rc.Managed.Provisioners { - ensure(pc.Type) - } - } - - // Must also visit our child modules, recursively. - for _, cc := range config.Children { - childDiags := loadProvisionerSchemas(schemas, cc, plugins) - diags = diags.Append(childDiags) - } - } - - return diags -} diff --git a/internal/terraform/schemas_test.go b/internal/terraform/schemas_test.go deleted file mode 100644 index 044b795a50a9..000000000000 --- a/internal/terraform/schemas_test.go +++ /dev/null @@ -1,65 +0,0 @@ -package terraform - -import ( - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/providers" -) - -func simpleTestSchemas() *Schemas { - provider := simpleMockProvider() - provisioner := simpleMockProvisioner() - - return &Schemas{ - Providers: map[addrs.Provider]*ProviderSchema{ - addrs.NewDefaultProvider("test"): provider.ProviderSchema(), - }, - Provisioners: map[string]*configschema.Block{ - "test": provisioner.GetSchemaResponse.Provisioner, - }, - } -} - -// schemaOnlyProvidersForTesting is a testing helper that constructs a -// plugin library that contains a set of providers that only know how to -// return schema, and will exhibit undefined behavior if used for any other -// purpose. -// -// The intended use for this is in testing components that use schemas to -// drive other behavior, such as reference analysis during graph construction, -// but that don't actually need to interact with providers otherwise. -func schemaOnlyProvidersForTesting(schemas map[addrs.Provider]*ProviderSchema) *contextPlugins { - factories := make(map[addrs.Provider]providers.Factory, len(schemas)) - - for providerAddr, schema := range schemas { - - resp := &providers.GetProviderSchemaResponse{ - Provider: providers.Schema{ - Block: schema.Provider, - }, - ResourceTypes: make(map[string]providers.Schema), - DataSources: make(map[string]providers.Schema), - } - for t, tSchema := range schema.ResourceTypes { - resp.ResourceTypes[t] = providers.Schema{ - Block: tSchema, - Version: int64(schema.ResourceTypeSchemaVersions[t]), - } - } - for t, tSchema := range schema.DataSources { - resp.DataSources[t] = providers.Schema{ - Block: tSchema, - } - } - - provider := &MockProvider{ - GetProviderSchemaResponse: resp, - } - - factories[providerAddr] = func() (providers.Interface, error) { - return provider, nil - } - } - - return newContextPlugins(factories, nil) -} diff --git a/internal/terraform/terraform_test.go b/internal/terraform/terraform_test.go deleted file mode 100644 index 419245958332..000000000000 --- a/internal/terraform/terraform_test.go +++ /dev/null @@ -1,1083 +0,0 @@ -package terraform - -import ( - "context" - "flag" - "io" - "os" - "path/filepath" - "strings" - "sync" - "testing" - - "github.com/davecgh/go-spew/spew" - "github.com/zclconf/go-cty/cty" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configload" - "github.com/hashicorp/terraform/internal/initwd" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/provisioners" - "github.com/hashicorp/terraform/internal/registry" - "github.com/hashicorp/terraform/internal/states" - - _ "github.com/hashicorp/terraform/internal/logging" -) - -// This is the directory where our test fixtures are. -const fixtureDir = "./testdata" - -func TestMain(m *testing.M) { - flag.Parse() - - // We have fmt.Stringer implementations on lots of objects that hide - // details that we very often want to see in tests, so we just disable - // spew's use of String methods globally on the assumption that spew - // usage implies an intent to see the raw values and ignore any - // abstractions. - spew.Config.DisableMethods = true - - os.Exit(m.Run()) -} - -func testModule(t *testing.T, name string) *configs.Config { - t.Helper() - c, _ := testModuleWithSnapshot(t, name) - return c -} - -func testModuleWithSnapshot(t *testing.T, name string) (*configs.Config, *configload.Snapshot) { - t.Helper() - - dir := filepath.Join(fixtureDir, name) - // FIXME: We're not dealing with the cleanup function here because - // this testModule function is used all over and so we don't want to - // change its interface at this late stage. - loader, _ := configload.NewLoaderForTests(t) - - // We need to be able to exercise experimental features in our integration tests. - loader.AllowLanguageExperiments(true) - - // Test modules usually do not refer to remote sources, and for local - // sources only this ultimately just records all of the module paths - // in a JSON file so that we can load them below. - inst := initwd.NewModuleInstaller(loader.ModulesDir(), registry.NewClient(nil, nil)) - _, instDiags := inst.InstallModules(context.Background(), dir, true, initwd.ModuleInstallHooksImpl{}) - if instDiags.HasErrors() { - t.Fatal(instDiags.Err()) - } - - // Since module installer has modified the module manifest on disk, we need - // to refresh the cache of it in the loader. - if err := loader.RefreshModules(); err != nil { - t.Fatalf("failed to refresh modules after installation: %s", err) - } - - config, snap, diags := loader.LoadConfigWithSnapshot(dir) - if diags.HasErrors() { - t.Fatal(diags.Error()) - } - - return config, snap -} - -// testModuleInline takes a map of path -> config strings and yields a config -// structure with those files loaded from disk -func testModuleInline(t *testing.T, sources map[string]string) *configs.Config { - t.Helper() - - cfgPath := t.TempDir() - - for path, configStr := range sources { - dir := filepath.Dir(path) - if dir != "." { - err := os.MkdirAll(filepath.Join(cfgPath, dir), os.FileMode(0777)) - if err != nil { - t.Fatalf("Error creating subdir: %s", err) - } - } - // Write the configuration - cfgF, err := os.Create(filepath.Join(cfgPath, path)) - if err != nil { - t.Fatalf("Error creating temporary file for config: %s", err) - } - - _, err = io.Copy(cfgF, strings.NewReader(configStr)) - cfgF.Close() - if err != nil { - t.Fatalf("Error creating temporary file for config: %s", err) - } - } - - loader, cleanup := configload.NewLoaderForTests(t) - defer cleanup() - - // We need to be able to exercise experimental features in our integration tests. - loader.AllowLanguageExperiments(true) - - // Test modules usually do not refer to remote sources, and for local - // sources only this ultimately just records all of the module paths - // in a JSON file so that we can load them below. - inst := initwd.NewModuleInstaller(loader.ModulesDir(), registry.NewClient(nil, nil)) - _, instDiags := inst.InstallModules(context.Background(), cfgPath, true, initwd.ModuleInstallHooksImpl{}) - if instDiags.HasErrors() { - t.Fatal(instDiags.Err()) - } - - // Since module installer has modified the module manifest on disk, we need - // to refresh the cache of it in the loader. - if err := loader.RefreshModules(); err != nil { - t.Fatalf("failed to refresh modules after installation: %s", err) - } - - config, diags := loader.LoadConfig(cfgPath) - if diags.HasErrors() { - t.Fatal(diags.Error()) - } - - return config -} - -// testSetResourceInstanceCurrent is a helper function for tests that sets a Current, -// Ready resource instance for the given module. -func testSetResourceInstanceCurrent(module *states.Module, resource, attrsJson, provider string) { - module.SetResourceInstanceCurrent( - mustResourceInstanceAddr(resource).Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(attrsJson), - }, - mustProviderConfig(provider), - ) -} - -// testSetResourceInstanceTainted is a helper function for tests that sets a Current, -// Tainted resource instance for the given module. -func testSetResourceInstanceTainted(module *states.Module, resource, attrsJson, provider string) { - module.SetResourceInstanceCurrent( - mustResourceInstanceAddr(resource).Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectTainted, - AttrsJSON: []byte(attrsJson), - }, - mustProviderConfig(provider), - ) -} - -func testProviderFuncFixed(rp providers.Interface) providers.Factory { - return func() (providers.Interface, error) { - if p, ok := rp.(*MockProvider); ok { - // make sure none of the methods were "called" on this new instance - p.GetProviderSchemaCalled = false - p.ValidateProviderConfigCalled = false - p.ValidateResourceConfigCalled = false - p.ValidateDataResourceConfigCalled = false - p.UpgradeResourceStateCalled = false - p.ConfigureProviderCalled = false - p.StopCalled = false - p.ReadResourceCalled = false - p.PlanResourceChangeCalled = false - p.ApplyResourceChangeCalled = false - p.ImportResourceStateCalled = false - p.ReadDataSourceCalled = false - p.CloseCalled = false - } - - return rp, nil - } -} - -func testProvisionerFuncFixed(rp *MockProvisioner) provisioners.Factory { - return func() (provisioners.Interface, error) { - // make sure this provisioner has has not been closed - rp.CloseCalled = false - return rp, nil - } -} - -func mustResourceInstanceAddr(s string) addrs.AbsResourceInstance { - addr, diags := addrs.ParseAbsResourceInstanceStr(s) - if diags.HasErrors() { - panic(diags.Err()) - } - return addr -} - -func mustConfigResourceAddr(s string) addrs.ConfigResource { - addr, diags := addrs.ParseAbsResourceStr(s) - if diags.HasErrors() { - panic(diags.Err()) - } - return addr.Config() -} - -func mustAbsResourceAddr(s string) addrs.AbsResource { - addr, diags := addrs.ParseAbsResourceStr(s) - if diags.HasErrors() { - panic(diags.Err()) - } - return addr -} - -func mustProviderConfig(s string) addrs.AbsProviderConfig { - p, diags := addrs.ParseAbsProviderConfigStr(s) - if diags.HasErrors() { - panic(diags.Err()) - } - return p -} - -// HookRecordApplyOrder is a test hook that records the order of applies -// by recording the PreApply event. -type HookRecordApplyOrder struct { - NilHook - - Active bool - - IDs []string - States []cty.Value - Diffs []*plans.Change - - l sync.Mutex -} - -func (h *HookRecordApplyOrder) PreApply(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) { - if plannedNewState.RawEquals(priorState) { - return HookActionContinue, nil - } - - if h.Active { - h.l.Lock() - defer h.l.Unlock() - - h.IDs = append(h.IDs, addr.String()) - h.Diffs = append(h.Diffs, &plans.Change{ - Action: action, - Before: priorState, - After: plannedNewState, - }) - h.States = append(h.States, priorState) - } - - return HookActionContinue, nil -} - -// Below are all the constant strings that are the expected output for -// various tests. - -const testTerraformInputProviderOnlyStr = ` -aws_instance.foo: - ID = - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = us-west-2 - type = -` - -const testTerraformApplyStr = ` -aws_instance.bar: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = bar - type = aws_instance -aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - num = 2 - type = aws_instance -` - -const testTerraformApplyDataBasicStr = ` -data.null_data_source.testing: - ID = yo - provider = provider["registry.terraform.io/hashicorp/null"] -` - -const testTerraformApplyRefCountStr = ` -aws_instance.bar: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = 3 - type = aws_instance - - Dependencies: - aws_instance.foo -aws_instance.foo.0: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance -aws_instance.foo.1: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance -aws_instance.foo.2: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance -` - -const testTerraformApplyProviderAliasStr = ` -aws_instance.bar: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"].bar - foo = bar - type = aws_instance -aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - num = 2 - type = aws_instance -` - -const testTerraformApplyProviderAliasConfigStr = ` -another_instance.bar: - ID = foo - provider = provider["registry.terraform.io/hashicorp/another"].two - type = another_instance -another_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/another"] - type = another_instance -` - -const testTerraformApplyEmptyModuleStr = ` - -Outputs: - -end = XXXX -` - -const testTerraformApplyDependsCreateBeforeStr = ` -aws_instance.lb: - ID = baz - provider = provider["registry.terraform.io/hashicorp/aws"] - instance = foo - type = aws_instance - - Dependencies: - aws_instance.web -aws_instance.web: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - require_new = ami-new - type = aws_instance -` - -const testTerraformApplyCreateBeforeStr = ` -aws_instance.bar: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - require_new = xyz - type = aws_instance -` - -const testTerraformApplyCreateBeforeUpdateStr = ` -aws_instance.bar: - ID = bar - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = baz - type = aws_instance -` - -const testTerraformApplyCancelStr = ` -aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance - value = 2 -` - -const testTerraformApplyComputeStr = ` -aws_instance.bar: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = computed_value - type = aws_instance - - Dependencies: - aws_instance.foo -aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - compute = value - compute_value = 1 - num = 2 - type = aws_instance - value = computed_value -` - -const testTerraformApplyCountDecStr = ` -aws_instance.bar: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = bar - type = aws_instance -aws_instance.foo.0: - ID = bar - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = foo - type = aws_instance -aws_instance.foo.1: - ID = bar - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = foo - type = aws_instance -` - -const testTerraformApplyCountDecToOneStr = ` -aws_instance.foo: - ID = bar - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = foo - type = aws_instance -` - -const testTerraformApplyCountDecToOneCorruptedStr = ` -aws_instance.foo: - ID = bar - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = foo - type = aws_instance -` - -const testTerraformApplyCountDecToOneCorruptedPlanStr = ` -DIFF: - -DESTROY: aws_instance.foo[0] - id: "baz" => "" - type: "aws_instance" => "" - - - -STATE: - -aws_instance.foo: - ID = bar - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = foo - type = aws_instance -aws_instance.foo.0: - ID = baz - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance -` - -const testTerraformApplyCountVariableStr = ` -aws_instance.foo.0: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = foo - type = aws_instance -aws_instance.foo.1: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = foo - type = aws_instance -` - -const testTerraformApplyCountVariableRefStr = ` -aws_instance.bar: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = 2 - type = aws_instance - - Dependencies: - aws_instance.foo -aws_instance.foo.0: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance -aws_instance.foo.1: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance -` -const testTerraformApplyForEachVariableStr = ` -aws_instance.foo["b15c6d616d6143248c575900dff57325eb1de498"]: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = foo - type = aws_instance -aws_instance.foo["c3de47d34b0a9f13918dd705c141d579dd6555fd"]: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = foo - type = aws_instance -aws_instance.foo["e30a7edcc42a846684f2a4eea5f3cd261d33c46d"]: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = foo - type = aws_instance -aws_instance.one["a"]: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance -aws_instance.one["b"]: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance -aws_instance.two["a"]: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance - - Dependencies: - aws_instance.one -aws_instance.two["b"]: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance - - Dependencies: - aws_instance.one` -const testTerraformApplyMinimalStr = ` -aws_instance.bar: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance -aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance -` - -const testTerraformApplyModuleStr = ` -aws_instance.bar: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = bar - type = aws_instance -aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - num = 2 - type = aws_instance - -module.child: - aws_instance.baz: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = bar - type = aws_instance -` - -const testTerraformApplyModuleBoolStr = ` -aws_instance.bar: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = true - type = aws_instance -` - -const testTerraformApplyModuleDestroyOrderStr = ` - -` - -const testTerraformApplyMultiProviderStr = ` -aws_instance.bar: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = bar - type = aws_instance -do_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/do"] - num = 2 - type = do_instance -` - -const testTerraformApplyModuleOnlyProviderStr = ` - -module.child: - aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance - test_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/test"] - type = test_instance -` - -const testTerraformApplyModuleProviderAliasStr = ` - -module.child: - aws_instance.foo: - ID = foo - provider = module.child.provider["registry.terraform.io/hashicorp/aws"].eu - type = aws_instance -` - -const testTerraformApplyModuleVarRefExistingStr = ` -aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = bar - type = aws_instance - -module.child: - aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance - value = bar - - Dependencies: - aws_instance.foo -` - -const testTerraformApplyOutputOrphanStr = ` - -Outputs: - -foo = bar -` - -const testTerraformApplyOutputOrphanModuleStr = ` - -` - -const testTerraformApplyProvisionerStr = ` -aws_instance.bar: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance - - Dependencies: - aws_instance.foo -aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - compute = value - compute_value = 1 - num = 2 - type = aws_instance - value = computed_value -` - -const testTerraformApplyProvisionerModuleStr = ` - -module.child: - aws_instance.bar: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance -` - -const testTerraformApplyProvisionerFailStr = ` -aws_instance.bar: (tainted) - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance -aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - num = 2 - type = aws_instance -` - -const testTerraformApplyProvisionerFailCreateStr = ` -aws_instance.bar: (tainted) - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance -` - -const testTerraformApplyProvisionerFailCreateNoIdStr = ` - -` - -const testTerraformApplyProvisionerFailCreateBeforeDestroyStr = ` -aws_instance.bar: (tainted) (1 deposed) - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - require_new = xyz - type = aws_instance - Deposed ID 1 = bar -` - -const testTerraformApplyProvisionerResourceRefStr = ` -aws_instance.bar: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - num = 2 - type = aws_instance -` - -const testTerraformApplyProvisionerSelfRefStr = ` -aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = bar - type = aws_instance -` - -const testTerraformApplyProvisionerMultiSelfRefStr = ` -aws_instance.foo.0: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = number 0 - type = aws_instance -aws_instance.foo.1: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = number 1 - type = aws_instance -aws_instance.foo.2: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = number 2 - type = aws_instance -` - -const testTerraformApplyProvisionerMultiSelfRefSingleStr = ` -aws_instance.foo.0: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = number 0 - type = aws_instance -aws_instance.foo.1: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = number 1 - type = aws_instance -aws_instance.foo.2: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = number 2 - type = aws_instance -` - -const testTerraformApplyProvisionerDiffStr = ` -aws_instance.bar: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = bar - type = aws_instance -` - -const testTerraformApplyProvisionerSensitiveStr = ` -aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance -` - -const testTerraformApplyDestroyStr = ` - -` - -const testTerraformApplyErrorStr = ` -aws_instance.bar: (tainted) - ID = - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = 2 - - Dependencies: - aws_instance.foo -aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance - value = 2 -` - -const testTerraformApplyErrorCreateBeforeDestroyStr = ` -aws_instance.bar: - ID = bar - provider = provider["registry.terraform.io/hashicorp/aws"] - require_new = abc - type = aws_instance -` - -const testTerraformApplyErrorDestroyCreateBeforeDestroyStr = ` -aws_instance.bar: (1 deposed) - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - require_new = xyz - type = aws_instance - Deposed ID 1 = bar -` - -const testTerraformApplyErrorPartialStr = ` -aws_instance.bar: - ID = bar - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance - - Dependencies: - aws_instance.foo -aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - type = aws_instance - value = 2 -` - -const testTerraformApplyResourceDependsOnModuleStr = ` -aws_instance.a: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - ami = parent - type = aws_instance - - Dependencies: - module.child.aws_instance.child - -module.child: - aws_instance.child: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - ami = child - type = aws_instance -` - -const testTerraformApplyResourceDependsOnModuleDeepStr = ` -aws_instance.a: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - ami = parent - type = aws_instance - - Dependencies: - module.child.module.grandchild.aws_instance.c - -module.child.grandchild: - aws_instance.c: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - ami = grandchild - type = aws_instance -` - -const testTerraformApplyResourceDependsOnModuleInModuleStr = ` - -module.child: - aws_instance.b: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - ami = child - type = aws_instance - - Dependencies: - module.child.module.grandchild.aws_instance.c -module.child.grandchild: - aws_instance.c: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - ami = grandchild - type = aws_instance -` - -const testTerraformApplyTaintStr = ` -aws_instance.bar: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - num = 2 - type = aws_instance -` - -const testTerraformApplyTaintDepStr = ` -aws_instance.bar: - ID = bar - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = foo - num = 2 - type = aws_instance - - Dependencies: - aws_instance.foo -aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - num = 2 - type = aws_instance -` - -const testTerraformApplyTaintDepRequireNewStr = ` -aws_instance.bar: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = foo - require_new = yes - type = aws_instance - - Dependencies: - aws_instance.foo -aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - num = 2 - type = aws_instance -` - -const testTerraformApplyOutputStr = ` -aws_instance.bar: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = bar - type = aws_instance -aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - num = 2 - type = aws_instance - -Outputs: - -foo_num = 2 -` - -const testTerraformApplyOutputAddStr = ` -aws_instance.test.0: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = foo0 - type = aws_instance -aws_instance.test.1: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = foo1 - type = aws_instance - -Outputs: - -firstOutput = foo0 -secondOutput = foo1 -` - -const testTerraformApplyOutputListStr = ` -aws_instance.bar.0: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = bar - type = aws_instance -aws_instance.bar.1: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = bar - type = aws_instance -aws_instance.bar.2: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = bar - type = aws_instance -aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - num = 2 - type = aws_instance - -Outputs: - -foo_num = [bar,bar,bar] -` - -const testTerraformApplyOutputMultiStr = ` -aws_instance.bar.0: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = bar - type = aws_instance -aws_instance.bar.1: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = bar - type = aws_instance -aws_instance.bar.2: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = bar - type = aws_instance -aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - num = 2 - type = aws_instance - -Outputs: - -foo_num = bar,bar,bar -` - -const testTerraformApplyOutputMultiIndexStr = ` -aws_instance.bar.0: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = bar - type = aws_instance -aws_instance.bar.1: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = bar - type = aws_instance -aws_instance.bar.2: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - foo = bar - type = aws_instance -aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - num = 2 - type = aws_instance - -Outputs: - -foo_num = bar -` - -const testTerraformApplyUnknownAttrStr = ` -aws_instance.foo: (tainted) - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - num = 2 - type = aws_instance -` - -const testTerraformApplyVarsStr = ` -aws_instance.bar: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - bar = override - baz = override - foo = us-east-1 -aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - bar = baz - list.# = 2 - list.0 = Hello - list.1 = World - map.Baz = Foo - map.Foo = Bar - map.Hello = World - num = 2 -` - -const testTerraformApplyVarsEnvStr = ` -aws_instance.bar: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] - list.# = 2 - list.0 = Hello - list.1 = World - map.Baz = Foo - map.Foo = Bar - map.Hello = World - string = baz - type = aws_instance -` - -const testTerraformRefreshDataRefDataStr = ` -data.null_data_source.bar: - ID = foo - provider = provider["registry.terraform.io/hashicorp/null"] - bar = yes -data.null_data_source.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/null"] - foo = yes -` diff --git a/internal/terraform/testdata/apply-blank/main.tf b/internal/terraform/testdata/apply-blank/main.tf deleted file mode 100644 index 0081db1861a6..000000000000 --- a/internal/terraform/testdata/apply-blank/main.tf +++ /dev/null @@ -1 +0,0 @@ -// Nothing! diff --git a/internal/terraform/testdata/apply-cancel-block/main.tf b/internal/terraform/testdata/apply-cancel-block/main.tf deleted file mode 100644 index 98f5ee87e9f0..000000000000 --- a/internal/terraform/testdata/apply-cancel-block/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_instance" "foo" { - num = "2" -} diff --git a/internal/terraform/testdata/apply-cancel-provisioner/main.tf b/internal/terraform/testdata/apply-cancel-provisioner/main.tf deleted file mode 100644 index dadabd882c01..000000000000 --- a/internal/terraform/testdata/apply-cancel-provisioner/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "foo" { - num = "2" - - provisioner "shell" { - foo = "bar" - } -} diff --git a/internal/terraform/testdata/apply-cancel/main.tf b/internal/terraform/testdata/apply-cancel/main.tf deleted file mode 100644 index 7c4af5f71a48..000000000000 --- a/internal/terraform/testdata/apply-cancel/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "foo" { - value = "2" -} - -resource "aws_instance" "bar" { - foo = "${aws_instance.foo.value}" -} diff --git a/internal/terraform/testdata/apply-cbd-count/main.tf b/internal/terraform/testdata/apply-cbd-count/main.tf deleted file mode 100644 index 058d3382c533..000000000000 --- a/internal/terraform/testdata/apply-cbd-count/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -resource "aws_instance" "bar" { - count = 2 - foo = "bar" - - lifecycle { - create_before_destroy = true - } -} diff --git a/internal/terraform/testdata/apply-cbd-cycle/main.tf b/internal/terraform/testdata/apply-cbd-cycle/main.tf deleted file mode 100644 index 5ac53107ebee..000000000000 --- a/internal/terraform/testdata/apply-cbd-cycle/main.tf +++ /dev/null @@ -1,19 +0,0 @@ -resource "test_instance" "a" { - foo = test_instance.b.id - require_new = "changed" - - lifecycle { - create_before_destroy = true - } -} - -resource "test_instance" "b" { - foo = test_instance.c.id - require_new = "changed" -} - - -resource "test_instance" "c" { - require_new = "changed" -} - diff --git a/internal/terraform/testdata/apply-cbd-depends-non-cbd/main.tf b/internal/terraform/testdata/apply-cbd-depends-non-cbd/main.tf deleted file mode 100644 index 6ba1b983fb85..000000000000 --- a/internal/terraform/testdata/apply-cbd-depends-non-cbd/main.tf +++ /dev/null @@ -1,12 +0,0 @@ -resource "aws_instance" "foo" { - require_new = "yes" -} - -resource "aws_instance" "bar" { - require_new = "yes" - value = "${aws_instance.foo.id}" - - lifecycle { - create_before_destroy = true - } -} diff --git a/internal/terraform/testdata/apply-cbd-deposed-only/main.tf b/internal/terraform/testdata/apply-cbd-deposed-only/main.tf deleted file mode 100644 index 0d2e2d3f92bf..000000000000 --- a/internal/terraform/testdata/apply-cbd-deposed-only/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -resource "aws_instance" "bar" { - lifecycle { - create_before_destroy = true - } -} diff --git a/internal/terraform/testdata/apply-compute/main.tf b/internal/terraform/testdata/apply-compute/main.tf deleted file mode 100644 index e785294ab44e..000000000000 --- a/internal/terraform/testdata/apply-compute/main.tf +++ /dev/null @@ -1,13 +0,0 @@ -variable "value" { - default = "" -} - -resource "aws_instance" "foo" { - num = "2" - compute = "value" - compute_value = "${var.value}" -} - -resource "aws_instance" "bar" { - foo = "${aws_instance.foo.value}" -} diff --git a/internal/terraform/testdata/apply-count-dec-one/main.tf b/internal/terraform/testdata/apply-count-dec-one/main.tf deleted file mode 100644 index 3b0fd9428595..000000000000 --- a/internal/terraform/testdata/apply-count-dec-one/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_instance" "foo" { - foo = "foo" -} diff --git a/internal/terraform/testdata/apply-count-dec/main.tf b/internal/terraform/testdata/apply-count-dec/main.tf deleted file mode 100644 index f18748c3b5cc..000000000000 --- a/internal/terraform/testdata/apply-count-dec/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -resource "aws_instance" "foo" { - foo = "foo" - count = 2 -} - -resource "aws_instance" "bar" { - foo = "bar" -} diff --git a/internal/terraform/testdata/apply-count-tainted/main.tf b/internal/terraform/testdata/apply-count-tainted/main.tf deleted file mode 100644 index ba35b034377a..000000000000 --- a/internal/terraform/testdata/apply-count-tainted/main.tf +++ /dev/null @@ -1,4 +0,0 @@ -resource "aws_instance" "foo" { - count = 2 - foo = "foo" -} diff --git a/internal/terraform/testdata/apply-count-variable-ref/main.tf b/internal/terraform/testdata/apply-count-variable-ref/main.tf deleted file mode 100644 index 8e9e4526612a..000000000000 --- a/internal/terraform/testdata/apply-count-variable-ref/main.tf +++ /dev/null @@ -1,11 +0,0 @@ -variable "foo" { - default = "2" -} - -resource "aws_instance" "foo" { - count = "${var.foo}" -} - -resource "aws_instance" "bar" { - foo = length(aws_instance.foo) -} diff --git a/internal/terraform/testdata/apply-count-variable/main.tf b/internal/terraform/testdata/apply-count-variable/main.tf deleted file mode 100644 index 6f322f2187f0..000000000000 --- a/internal/terraform/testdata/apply-count-variable/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -variable "foo" { - default = "2" -} - -resource "aws_instance" "foo" { - foo = "foo" - count = "${var.foo}" -} diff --git a/internal/terraform/testdata/apply-data-basic/main.tf b/internal/terraform/testdata/apply-data-basic/main.tf deleted file mode 100644 index 0c3bd8817ec8..000000000000 --- a/internal/terraform/testdata/apply-data-basic/main.tf +++ /dev/null @@ -1 +0,0 @@ -data "null_data_source" "testing" {} diff --git a/internal/terraform/testdata/apply-data-sensitive/main.tf b/internal/terraform/testdata/apply-data-sensitive/main.tf deleted file mode 100644 index c248a7c3316a..000000000000 --- a/internal/terraform/testdata/apply-data-sensitive/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -variable "foo" { - sensitive = true - default = "foo" -} - -data "null_data_source" "testing" { - foo = var.foo -} diff --git a/internal/terraform/testdata/apply-depends-create-before/main.tf b/internal/terraform/testdata/apply-depends-create-before/main.tf deleted file mode 100644 index 63478d893d9c..000000000000 --- a/internal/terraform/testdata/apply-depends-create-before/main.tf +++ /dev/null @@ -1,10 +0,0 @@ -resource "aws_instance" "web" { - require_new = "ami-new" - lifecycle { - create_before_destroy = true - } -} - -resource "aws_instance" "lb" { - instance = aws_instance.web.id -} diff --git a/internal/terraform/testdata/apply-destroy-cbd/main.tf b/internal/terraform/testdata/apply-destroy-cbd/main.tf deleted file mode 100644 index 3c7a46f7c170..000000000000 --- a/internal/terraform/testdata/apply-destroy-cbd/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "foo" { } -resource "aws_instance" "bar" { - depends_on = ["aws_instance.foo"] - lifecycle { - create_before_destroy = true - } -} diff --git a/internal/terraform/testdata/apply-destroy-computed/child/main.tf b/internal/terraform/testdata/apply-destroy-computed/child/main.tf deleted file mode 100644 index 5cd1f02b666c..000000000000 --- a/internal/terraform/testdata/apply-destroy-computed/child/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -variable "value" {} - -resource "aws_instance" "bar" { - value = "${var.value}" -} diff --git a/internal/terraform/testdata/apply-destroy-computed/main.tf b/internal/terraform/testdata/apply-destroy-computed/main.tf deleted file mode 100644 index 768c9680d801..000000000000 --- a/internal/terraform/testdata/apply-destroy-computed/main.tf +++ /dev/null @@ -1,6 +0,0 @@ -resource "aws_instance" "foo" {} - -module "child" { - source = "./child" - value = "${aws_instance.foo.output}" -} diff --git a/internal/terraform/testdata/apply-destroy-cross-providers/child/main.tf b/internal/terraform/testdata/apply-destroy-cross-providers/child/main.tf deleted file mode 100644 index 048b26dec80a..000000000000 --- a/internal/terraform/testdata/apply-destroy-cross-providers/child/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -variable "value" {} - -resource "aws_vpc" "bar" { - value = "${var.value}" -} diff --git a/internal/terraform/testdata/apply-destroy-cross-providers/main.tf b/internal/terraform/testdata/apply-destroy-cross-providers/main.tf deleted file mode 100644 index 1ff123a73b59..000000000000 --- a/internal/terraform/testdata/apply-destroy-cross-providers/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "shared" { -} - -module "child" { - source = "./child" - value = "${aws_instance.shared.id}" -} diff --git a/internal/terraform/testdata/apply-destroy-data-cycle/main.tf b/internal/terraform/testdata/apply-destroy-data-cycle/main.tf deleted file mode 100644 index 591af82004a4..000000000000 --- a/internal/terraform/testdata/apply-destroy-data-cycle/main.tf +++ /dev/null @@ -1,14 +0,0 @@ -locals { - l = data.null_data_source.d.id -} - -data "null_data_source" "d" { -} - -resource "null_resource" "a" { - count = local.l == "NONE" ? 1 : 0 -} - -provider "test" { - foo = data.null_data_source.d.id -} diff --git a/internal/terraform/testdata/apply-destroy-data-resource/main.tf b/internal/terraform/testdata/apply-destroy-data-resource/main.tf deleted file mode 100644 index 0d941a707746..000000000000 --- a/internal/terraform/testdata/apply-destroy-data-resource/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -data "null_data_source" "testing" { - foo = "yes" -} diff --git a/internal/terraform/testdata/apply-destroy-deeply-nested-module/child/main.tf b/internal/terraform/testdata/apply-destroy-deeply-nested-module/child/main.tf deleted file mode 100644 index 3694951f572f..000000000000 --- a/internal/terraform/testdata/apply-destroy-deeply-nested-module/child/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -module "subchild" { - source = "./subchild" -} diff --git a/internal/terraform/testdata/apply-destroy-deeply-nested-module/child/subchild/main.tf b/internal/terraform/testdata/apply-destroy-deeply-nested-module/child/subchild/main.tf deleted file mode 100644 index d31b87e0c640..000000000000 --- a/internal/terraform/testdata/apply-destroy-deeply-nested-module/child/subchild/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -/* -module "subsubchild" { - source = "./subsubchild" -} -*/ diff --git a/internal/terraform/testdata/apply-destroy-deeply-nested-module/child/subchild/subsubchild/main.tf b/internal/terraform/testdata/apply-destroy-deeply-nested-module/child/subchild/subsubchild/main.tf deleted file mode 100644 index 6ff716a4d4c1..000000000000 --- a/internal/terraform/testdata/apply-destroy-deeply-nested-module/child/subchild/subsubchild/main.tf +++ /dev/null @@ -1 +0,0 @@ -resource "aws_instance" "bar" {} diff --git a/internal/terraform/testdata/apply-destroy-deeply-nested-module/main.tf b/internal/terraform/testdata/apply-destroy-deeply-nested-module/main.tf deleted file mode 100644 index 1f95749fa7ea..000000000000 --- a/internal/terraform/testdata/apply-destroy-deeply-nested-module/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -module "child" { - source = "./child" -} diff --git a/internal/terraform/testdata/apply-destroy-depends-on/main.tf b/internal/terraform/testdata/apply-destroy-depends-on/main.tf deleted file mode 100644 index 3c3ee656f5b9..000000000000 --- a/internal/terraform/testdata/apply-destroy-depends-on/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -resource "aws_instance" "foo" { - depends_on = ["aws_instance.bar"] -} - -resource "aws_instance" "bar" {} diff --git a/internal/terraform/testdata/apply-destroy-mod-var-and-count-nested/child/child2/main.tf b/internal/terraform/testdata/apply-destroy-mod-var-and-count-nested/child/child2/main.tf deleted file mode 100644 index 6a4f91d5e903..000000000000 --- a/internal/terraform/testdata/apply-destroy-mod-var-and-count-nested/child/child2/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -variable "mod_count_child2" { } - -resource "aws_instance" "foo" { - count = "${var.mod_count_child2}" -} diff --git a/internal/terraform/testdata/apply-destroy-mod-var-and-count-nested/child/main.tf b/internal/terraform/testdata/apply-destroy-mod-var-and-count-nested/child/main.tf deleted file mode 100644 index 28b526795806..000000000000 --- a/internal/terraform/testdata/apply-destroy-mod-var-and-count-nested/child/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -variable "mod_count_child" { } - -module "child2" { - source = "./child2" - mod_count_child2 = "${var.mod_count_child}" -} - -resource "aws_instance" "foo" { } diff --git a/internal/terraform/testdata/apply-destroy-mod-var-and-count-nested/main.tf b/internal/terraform/testdata/apply-destroy-mod-var-and-count-nested/main.tf deleted file mode 100644 index 58600cdb94a0..000000000000 --- a/internal/terraform/testdata/apply-destroy-mod-var-and-count-nested/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -variable "mod_count_root" { - type = string - default = "3" -} - -module "child" { - source = "./child" - mod_count_child = var.mod_count_root -} diff --git a/internal/terraform/testdata/apply-destroy-mod-var-and-count/child/main.tf b/internal/terraform/testdata/apply-destroy-mod-var-and-count/child/main.tf deleted file mode 100644 index 67dac02a2754..000000000000 --- a/internal/terraform/testdata/apply-destroy-mod-var-and-count/child/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -variable "mod_count" { } - -resource "aws_instance" "foo" { - count = "${var.mod_count}" -} diff --git a/internal/terraform/testdata/apply-destroy-mod-var-and-count/main.tf b/internal/terraform/testdata/apply-destroy-mod-var-and-count/main.tf deleted file mode 100644 index 918b40d06711..000000000000 --- a/internal/terraform/testdata/apply-destroy-mod-var-and-count/main.tf +++ /dev/null @@ -1,4 +0,0 @@ -module "child" { - source = "./child" - mod_count = "3" -} diff --git a/internal/terraform/testdata/apply-destroy-mod-var-provider-config/child/child.tf b/internal/terraform/testdata/apply-destroy-mod-var-provider-config/child/child.tf deleted file mode 100644 index 6544cf6cb45f..000000000000 --- a/internal/terraform/testdata/apply-destroy-mod-var-provider-config/child/child.tf +++ /dev/null @@ -1,7 +0,0 @@ -variable "input" {} - -provider "aws" { - region = "us-east-${var.input}" -} - -resource "aws_instance" "foo" { } diff --git a/internal/terraform/testdata/apply-destroy-mod-var-provider-config/main.tf b/internal/terraform/testdata/apply-destroy-mod-var-provider-config/main.tf deleted file mode 100644 index 1e2dfb3521df..000000000000 --- a/internal/terraform/testdata/apply-destroy-mod-var-provider-config/main.tf +++ /dev/null @@ -1,4 +0,0 @@ -module "child" { - source = "./child" - input = "1" -} diff --git a/internal/terraform/testdata/apply-destroy-module-resource-prefix/child/main.tf b/internal/terraform/testdata/apply-destroy-module-resource-prefix/child/main.tf deleted file mode 100644 index 919f140bba6b..000000000000 --- a/internal/terraform/testdata/apply-destroy-module-resource-prefix/child/main.tf +++ /dev/null @@ -1 +0,0 @@ -resource "aws_instance" "foo" {} diff --git a/internal/terraform/testdata/apply-destroy-module-resource-prefix/main.tf b/internal/terraform/testdata/apply-destroy-module-resource-prefix/main.tf deleted file mode 100644 index 0f6991c536ca..000000000000 --- a/internal/terraform/testdata/apply-destroy-module-resource-prefix/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -module "child" { - source = "./child" -} diff --git a/internal/terraform/testdata/apply-destroy-module-with-attrs/child/main.tf b/internal/terraform/testdata/apply-destroy-module-with-attrs/child/main.tf deleted file mode 100644 index 55fa601707ff..000000000000 --- a/internal/terraform/testdata/apply-destroy-module-with-attrs/child/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -variable "vpc_id" {} - -resource "aws_instance" "child" { - vpc_id = var.vpc_id -} - -output "modout" { - value = aws_instance.child.id -} diff --git a/internal/terraform/testdata/apply-destroy-module-with-attrs/main.tf b/internal/terraform/testdata/apply-destroy-module-with-attrs/main.tf deleted file mode 100644 index 9b2d46db7414..000000000000 --- a/internal/terraform/testdata/apply-destroy-module-with-attrs/main.tf +++ /dev/null @@ -1,10 +0,0 @@ -resource "aws_instance" "vpc" { } - -module "child" { - source = "./child" - vpc_id = aws_instance.vpc.id -} - -output "out" { - value = module.child.modout -} diff --git a/internal/terraform/testdata/apply-destroy-nested-module-with-attrs/middle/bottom/bottom.tf b/internal/terraform/testdata/apply-destroy-nested-module-with-attrs/middle/bottom/bottom.tf deleted file mode 100644 index b5db44ee33e6..000000000000 --- a/internal/terraform/testdata/apply-destroy-nested-module-with-attrs/middle/bottom/bottom.tf +++ /dev/null @@ -1,5 +0,0 @@ -variable bottom_param {} - -resource "null_resource" "bottom" { - value = "${var.bottom_param}" -} diff --git a/internal/terraform/testdata/apply-destroy-nested-module-with-attrs/middle/middle.tf b/internal/terraform/testdata/apply-destroy-nested-module-with-attrs/middle/middle.tf deleted file mode 100644 index 76652ee443df..000000000000 --- a/internal/terraform/testdata/apply-destroy-nested-module-with-attrs/middle/middle.tf +++ /dev/null @@ -1,10 +0,0 @@ -variable param {} - -module "bottom" { - source = "./bottom" - bottom_param = "${var.param}" -} - -resource "null_resource" "middle" { - value = "${var.param}" -} diff --git a/internal/terraform/testdata/apply-destroy-nested-module-with-attrs/top.tf b/internal/terraform/testdata/apply-destroy-nested-module-with-attrs/top.tf deleted file mode 100644 index 1b631f4d5c08..000000000000 --- a/internal/terraform/testdata/apply-destroy-nested-module-with-attrs/top.tf +++ /dev/null @@ -1,4 +0,0 @@ -module "middle" { - source = "./middle" - param = "foo" -} diff --git a/internal/terraform/testdata/apply-destroy-nested-module/child/main.tf b/internal/terraform/testdata/apply-destroy-nested-module/child/main.tf deleted file mode 100644 index 852bce8b9f39..000000000000 --- a/internal/terraform/testdata/apply-destroy-nested-module/child/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -module "subchild" { - source = "./subchild" -} diff --git a/internal/terraform/testdata/apply-destroy-nested-module/child/subchild/main.tf b/internal/terraform/testdata/apply-destroy-nested-module/child/subchild/main.tf deleted file mode 100644 index 6ff716a4d4c1..000000000000 --- a/internal/terraform/testdata/apply-destroy-nested-module/child/subchild/main.tf +++ /dev/null @@ -1 +0,0 @@ -resource "aws_instance" "bar" {} diff --git a/internal/terraform/testdata/apply-destroy-nested-module/main.tf b/internal/terraform/testdata/apply-destroy-nested-module/main.tf deleted file mode 100644 index 8a5a1b2e5be7..000000000000 --- a/internal/terraform/testdata/apply-destroy-nested-module/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -/* -module "child" { - source = "./child" -} -*/ diff --git a/internal/terraform/testdata/apply-destroy-outputs/main.tf b/internal/terraform/testdata/apply-destroy-outputs/main.tf deleted file mode 100644 index 8a0384798eaf..000000000000 --- a/internal/terraform/testdata/apply-destroy-outputs/main.tf +++ /dev/null @@ -1,34 +0,0 @@ -data "test_data_source" "bar" { - for_each = { - a = "b" - } - foo = "zing" -} - -data "test_data_source" "foo" { - for_each = data.test_data_source.bar - foo = "ok" -} - -locals { - l = [ - { - name = data.test_data_source.foo["a"].id - val = "null" - }, - ] - - m = { for v in local.l : - v.name => v - } -} - -resource "test_instance" "bar" { - for_each = local.m - foo = format("%s", each.value.name) - dep = each.value.val -} - -output "out" { - value = test_instance.bar -} diff --git a/internal/terraform/testdata/apply-destroy-provisioner/main.tf b/internal/terraform/testdata/apply-destroy-provisioner/main.tf deleted file mode 100644 index 51b29c72a082..000000000000 --- a/internal/terraform/testdata/apply-destroy-provisioner/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_instance" "foo" { - provisioner "shell" {} -} diff --git a/internal/terraform/testdata/apply-destroy-tainted/main.tf b/internal/terraform/testdata/apply-destroy-tainted/main.tf deleted file mode 100644 index 48f4f13783e0..000000000000 --- a/internal/terraform/testdata/apply-destroy-tainted/main.tf +++ /dev/null @@ -1,17 +0,0 @@ -resource "test_instance" "a" { - foo = "a" -} - -resource "test_instance" "b" { - foo = "b" - lifecycle { - create_before_destroy = true - } -} - -resource "test_instance" "c" { - foo = "c" - lifecycle { - create_before_destroy = true - } -} diff --git a/internal/terraform/testdata/apply-destroy-targeted-count/main.tf b/internal/terraform/testdata/apply-destroy-targeted-count/main.tf deleted file mode 100644 index 680d30ffaa36..000000000000 --- a/internal/terraform/testdata/apply-destroy-targeted-count/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "foo" { - count = 3 -} - -resource "aws_instance" "bar" { - foo = ["${aws_instance.foo.*.id}"] -} diff --git a/internal/terraform/testdata/apply-destroy-with-locals/main.tf b/internal/terraform/testdata/apply-destroy-with-locals/main.tf deleted file mode 100644 index 1ab75187155e..000000000000 --- a/internal/terraform/testdata/apply-destroy-with-locals/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -locals { - name = "test-${aws_instance.foo.id}" -} -resource "aws_instance" "foo" {} - -output "name" { - value = "${local.name}" -} diff --git a/internal/terraform/testdata/apply-destroy/main.tf b/internal/terraform/testdata/apply-destroy/main.tf deleted file mode 100644 index 1b6cdae67b0e..000000000000 --- a/internal/terraform/testdata/apply-destroy/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "foo" { - num = "2" -} - -resource "aws_instance" "bar" { - foo = "${aws_instance.foo.num}" -} diff --git a/internal/terraform/testdata/apply-empty-module/child/main.tf b/internal/terraform/testdata/apply-empty-module/child/main.tf deleted file mode 100644 index 6db38ea162c5..000000000000 --- a/internal/terraform/testdata/apply-empty-module/child/main.tf +++ /dev/null @@ -1,11 +0,0 @@ -output "aws_route53_zone_id" { - value = "XXXX" -} - -output "aws_access_key" { - value = "YYYYY" -} - -output "aws_secret_key" { - value = "ZZZZ" -} diff --git a/internal/terraform/testdata/apply-empty-module/main.tf b/internal/terraform/testdata/apply-empty-module/main.tf deleted file mode 100644 index 50ce84f0bc3f..000000000000 --- a/internal/terraform/testdata/apply-empty-module/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -module "child" { - source = "./child" -} - -output "end" { - value = "${module.child.aws_route53_zone_id}" -} diff --git a/internal/terraform/testdata/apply-error-create-before/main.tf b/internal/terraform/testdata/apply-error-create-before/main.tf deleted file mode 100644 index c7c2776eb773..000000000000 --- a/internal/terraform/testdata/apply-error-create-before/main.tf +++ /dev/null @@ -1,6 +0,0 @@ -resource "aws_instance" "bar" { - require_new = "xyz" - lifecycle { - create_before_destroy = true - } -} diff --git a/internal/terraform/testdata/apply-error/main.tf b/internal/terraform/testdata/apply-error/main.tf deleted file mode 100644 index 7c4af5f71a48..000000000000 --- a/internal/terraform/testdata/apply-error/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "foo" { - value = "2" -} - -resource "aws_instance" "bar" { - foo = "${aws_instance.foo.value}" -} diff --git a/internal/terraform/testdata/apply-escape/main.tf b/internal/terraform/testdata/apply-escape/main.tf deleted file mode 100644 index bca2c9b7e27c..000000000000 --- a/internal/terraform/testdata/apply-escape/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_instance" "bar" { - foo = "${"\"bar\""}" -} diff --git a/internal/terraform/testdata/apply-good-create-before-update/main.tf b/internal/terraform/testdata/apply-good-create-before-update/main.tf deleted file mode 100644 index d0a2fc937668..000000000000 --- a/internal/terraform/testdata/apply-good-create-before-update/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "bar" { - foo = "baz" - - lifecycle { - create_before_destroy = true - } -} diff --git a/internal/terraform/testdata/apply-good-create-before/main.tf b/internal/terraform/testdata/apply-good-create-before/main.tf deleted file mode 100644 index c7c2776eb773..000000000000 --- a/internal/terraform/testdata/apply-good-create-before/main.tf +++ /dev/null @@ -1,6 +0,0 @@ -resource "aws_instance" "bar" { - require_new = "xyz" - lifecycle { - create_before_destroy = true - } -} diff --git a/internal/terraform/testdata/apply-good/main.tf b/internal/terraform/testdata/apply-good/main.tf deleted file mode 100644 index 5c22c19d109e..000000000000 --- a/internal/terraform/testdata/apply-good/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "foo" { - num = 2 -} - -resource "aws_instance" "bar" { - foo = "bar" -} diff --git a/internal/terraform/testdata/apply-idattr/main.tf b/internal/terraform/testdata/apply-idattr/main.tf deleted file mode 100644 index 1c49f3975554..000000000000 --- a/internal/terraform/testdata/apply-idattr/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_instance" "foo" { - num = 42 -} diff --git a/internal/terraform/testdata/apply-ignore-changes-all/main.tf b/internal/terraform/testdata/apply-ignore-changes-all/main.tf deleted file mode 100644 index a89889a09be3..000000000000 --- a/internal/terraform/testdata/apply-ignore-changes-all/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "foo" { - required_field = "set" - - lifecycle { - ignore_changes = all - } -} diff --git a/internal/terraform/testdata/apply-ignore-changes-create/main.tf b/internal/terraform/testdata/apply-ignore-changes-create/main.tf deleted file mode 100644 index d470660ec1cc..000000000000 --- a/internal/terraform/testdata/apply-ignore-changes-create/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "foo" { - required_field = "set" - - lifecycle { - ignore_changes = ["required_field"] - } -} diff --git a/internal/terraform/testdata/apply-ignore-changes-dep/main.tf b/internal/terraform/testdata/apply-ignore-changes-dep/main.tf deleted file mode 100644 index 097d48942839..000000000000 --- a/internal/terraform/testdata/apply-ignore-changes-dep/main.tf +++ /dev/null @@ -1,12 +0,0 @@ -resource "aws_instance" "foo" { - count = 2 - ami = "ami-bcd456" - lifecycle { - ignore_changes = ["ami"] - } -} - -resource "aws_eip" "foo" { - count = 2 - instance = "${aws_instance.foo.*.id[count.index]}" -} diff --git a/internal/terraform/testdata/apply-inconsistent-with-plan/main.tf b/internal/terraform/testdata/apply-inconsistent-with-plan/main.tf deleted file mode 100644 index 9284072dc9c1..000000000000 --- a/internal/terraform/testdata/apply-inconsistent-with-plan/main.tf +++ /dev/null @@ -1,2 +0,0 @@ -resource "test" "foo" { -} diff --git a/internal/terraform/testdata/apply-interpolated-count/main.tf b/internal/terraform/testdata/apply-interpolated-count/main.tf deleted file mode 100644 index 527a0b84205c..000000000000 --- a/internal/terraform/testdata/apply-interpolated-count/main.tf +++ /dev/null @@ -1,11 +0,0 @@ -variable "instance_count" { - default = 1 -} - -resource "aws_instance" "test" { - count = "${var.instance_count}" -} - -resource "aws_instance" "dependent" { - count = "${length(aws_instance.test)}" -} diff --git a/internal/terraform/testdata/apply-invalid-index/main.tf b/internal/terraform/testdata/apply-invalid-index/main.tf deleted file mode 100644 index 8ea02d77384e..000000000000 --- a/internal/terraform/testdata/apply-invalid-index/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "test_instance" "a" { - count = 0 -} - -resource "test_instance" "b" { - value = test_instance.a[0].value -} diff --git a/internal/terraform/testdata/apply-issue19908/issue19908.tf b/internal/terraform/testdata/apply-issue19908/issue19908.tf deleted file mode 100644 index 0c802fb653fa..000000000000 --- a/internal/terraform/testdata/apply-issue19908/issue19908.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "test" "foo" { - baz = "updated" -} diff --git a/internal/terraform/testdata/apply-local-val/child/child.tf b/internal/terraform/testdata/apply-local-val/child/child.tf deleted file mode 100644 index f7febc42f656..000000000000 --- a/internal/terraform/testdata/apply-local-val/child/child.tf +++ /dev/null @@ -1,4 +0,0 @@ - -output "result" { - value = "hello" -} diff --git a/internal/terraform/testdata/apply-local-val/main.tf b/internal/terraform/testdata/apply-local-val/main.tf deleted file mode 100644 index 51ca2dedcf3a..000000000000 --- a/internal/terraform/testdata/apply-local-val/main.tf +++ /dev/null @@ -1,10 +0,0 @@ - -module "child" { - source = "./child" -} - -locals { - result_1 = "${module.child.result}" - result_2 = "${local.result_1}" - result_3 = "${local.result_2} world" -} diff --git a/internal/terraform/testdata/apply-local-val/outputs.tf b/internal/terraform/testdata/apply-local-val/outputs.tf deleted file mode 100644 index f0078c190b39..000000000000 --- a/internal/terraform/testdata/apply-local-val/outputs.tf +++ /dev/null @@ -1,9 +0,0 @@ -# These are in a separate file to make sure config merging is working properly - -output "result_1" { - value = "${local.result_1}" -} - -output "result_3" { - value = "${local.result_3}" -} diff --git a/internal/terraform/testdata/apply-map-var-through-module/amodule/main.tf b/internal/terraform/testdata/apply-map-var-through-module/amodule/main.tf deleted file mode 100644 index a5284966ed08..000000000000 --- a/internal/terraform/testdata/apply-map-var-through-module/amodule/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -variable "amis" { - type = map(string) -} - -resource "null_resource" "noop" {} - -output "amis_out" { - value = var.amis -} diff --git a/internal/terraform/testdata/apply-map-var-through-module/main.tf b/internal/terraform/testdata/apply-map-var-through-module/main.tf deleted file mode 100644 index 4cec4a678b0d..000000000000 --- a/internal/terraform/testdata/apply-map-var-through-module/main.tf +++ /dev/null @@ -1,19 +0,0 @@ -variable "amis_in" { - type = map(string) - default = { - "us-west-1" = "ami-123456" - "us-west-2" = "ami-456789" - "eu-west-1" = "ami-789012" - "eu-west-2" = "ami-989484" - } -} - -module "test" { - source = "./amodule" - - amis = var.amis_in -} - -output "amis_from_module" { - value = module.test.amis_out -} diff --git a/internal/terraform/testdata/apply-minimal/main.tf b/internal/terraform/testdata/apply-minimal/main.tf deleted file mode 100644 index 88002d078a1b..000000000000 --- a/internal/terraform/testdata/apply-minimal/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -resource "aws_instance" "foo" { -} - -resource "aws_instance" "bar" { -} diff --git a/internal/terraform/testdata/apply-module-bool/child/main.tf b/internal/terraform/testdata/apply-module-bool/child/main.tf deleted file mode 100644 index d2a38434c296..000000000000 --- a/internal/terraform/testdata/apply-module-bool/child/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -variable "leader" { - default = false -} - -output "leader" { - value = "${var.leader}" -} diff --git a/internal/terraform/testdata/apply-module-bool/main.tf b/internal/terraform/testdata/apply-module-bool/main.tf deleted file mode 100644 index 1d40cd4f4ae1..000000000000 --- a/internal/terraform/testdata/apply-module-bool/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -module "child" { - source = "./child" - leader = true -} - -resource "aws_instance" "bar" { - foo = "${module.child.leader}" -} diff --git a/internal/terraform/testdata/apply-module-depends-on/main.tf b/internal/terraform/testdata/apply-module-depends-on/main.tf deleted file mode 100644 index 9f7102d531cf..000000000000 --- a/internal/terraform/testdata/apply-module-depends-on/main.tf +++ /dev/null @@ -1,32 +0,0 @@ -module "moda" { - source = "./moda" - depends_on = [test_instance.a, module.modb] -} - -resource "test_instance" "a" { - depends_on = [module.modb] - num = 4 - foo = test_instance.aa.id -} - -resource "test_instance" "aa" { - num = 3 - foo = module.modb.out -} - -module "modb" { - source = "./modb" - depends_on = [test_instance.b] -} - -resource "test_instance" "b" { - num = 1 -} - -output "moda_data" { - value = module.moda.out -} - -output "modb_resource" { - value = module.modb.out -} diff --git a/internal/terraform/testdata/apply-module-depends-on/moda/main.tf b/internal/terraform/testdata/apply-module-depends-on/moda/main.tf deleted file mode 100644 index e60d300bae2c..000000000000 --- a/internal/terraform/testdata/apply-module-depends-on/moda/main.tf +++ /dev/null @@ -1,11 +0,0 @@ -resource "test_instance" "a" { - num = 5 -} - -data "test_data_source" "a" { - foo = "a" -} - -output "out" { - value = data.test_data_source.a.id -} diff --git a/internal/terraform/testdata/apply-module-depends-on/modb/main.tf b/internal/terraform/testdata/apply-module-depends-on/modb/main.tf deleted file mode 100644 index 961c5d560bd7..000000000000 --- a/internal/terraform/testdata/apply-module-depends-on/modb/main.tf +++ /dev/null @@ -1,11 +0,0 @@ -resource "test_instance" "b" { - num = 2 -} - -data "test_data_source" "b" { - foo = "b" -} - -output "out" { - value = test_instance.b.id -} diff --git a/internal/terraform/testdata/apply-module-destroy-order/child/main.tf b/internal/terraform/testdata/apply-module-destroy-order/child/main.tf deleted file mode 100644 index 0b2a8bc07dd1..000000000000 --- a/internal/terraform/testdata/apply-module-destroy-order/child/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "a" { - id = "a" -} - -output "a_output" { - value = "${aws_instance.a.id}" -} diff --git a/internal/terraform/testdata/apply-module-destroy-order/main.tf b/internal/terraform/testdata/apply-module-destroy-order/main.tf deleted file mode 100644 index 2c47edadff9a..000000000000 --- a/internal/terraform/testdata/apply-module-destroy-order/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -module "child" { - source = "./child" -} - -resource "aws_instance" "b" { - id = "b" - blah = "${module.child.a_output}" -} diff --git a/internal/terraform/testdata/apply-module-grandchild-provider-inherit/child/grandchild/main.tf b/internal/terraform/testdata/apply-module-grandchild-provider-inherit/child/grandchild/main.tf deleted file mode 100644 index 919f140bba6b..000000000000 --- a/internal/terraform/testdata/apply-module-grandchild-provider-inherit/child/grandchild/main.tf +++ /dev/null @@ -1 +0,0 @@ -resource "aws_instance" "foo" {} diff --git a/internal/terraform/testdata/apply-module-grandchild-provider-inherit/child/main.tf b/internal/terraform/testdata/apply-module-grandchild-provider-inherit/child/main.tf deleted file mode 100644 index b422300ec984..000000000000 --- a/internal/terraform/testdata/apply-module-grandchild-provider-inherit/child/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -module "grandchild" { - source = "./grandchild" -} diff --git a/internal/terraform/testdata/apply-module-grandchild-provider-inherit/main.tf b/internal/terraform/testdata/apply-module-grandchild-provider-inherit/main.tf deleted file mode 100644 index 25d0993d1e40..000000000000 --- a/internal/terraform/testdata/apply-module-grandchild-provider-inherit/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -provider "aws" { - value = "foo" -} - -module "child" { - source = "./child" -} diff --git a/internal/terraform/testdata/apply-module-only-provider/child/main.tf b/internal/terraform/testdata/apply-module-only-provider/child/main.tf deleted file mode 100644 index e15099c171b3..000000000000 --- a/internal/terraform/testdata/apply-module-only-provider/child/main.tf +++ /dev/null @@ -1,2 +0,0 @@ -resource "aws_instance" "foo" {} -resource "test_instance" "foo" {} diff --git a/internal/terraform/testdata/apply-module-only-provider/main.tf b/internal/terraform/testdata/apply-module-only-provider/main.tf deleted file mode 100644 index 2276b5f36ca2..000000000000 --- a/internal/terraform/testdata/apply-module-only-provider/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -provider "aws" {} - -module "child" { - source = "./child" -} diff --git a/internal/terraform/testdata/apply-module-orphan-provider-inherit/main.tf b/internal/terraform/testdata/apply-module-orphan-provider-inherit/main.tf deleted file mode 100644 index e334ff2c77b8..000000000000 --- a/internal/terraform/testdata/apply-module-orphan-provider-inherit/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -provider "aws" { - value = "foo" -} diff --git a/internal/terraform/testdata/apply-module-provider-alias/child/main.tf b/internal/terraform/testdata/apply-module-provider-alias/child/main.tf deleted file mode 100644 index ee923f255ae8..000000000000 --- a/internal/terraform/testdata/apply-module-provider-alias/child/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -provider "aws" { - alias = "eu" -} - -resource "aws_instance" "foo" { - provider = "aws.eu" -} diff --git a/internal/terraform/testdata/apply-module-provider-alias/main.tf b/internal/terraform/testdata/apply-module-provider-alias/main.tf deleted file mode 100644 index 0f6991c536ca..000000000000 --- a/internal/terraform/testdata/apply-module-provider-alias/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -module "child" { - source = "./child" -} diff --git a/internal/terraform/testdata/apply-module-provider-close-nested/child/main.tf b/internal/terraform/testdata/apply-module-provider-close-nested/child/main.tf deleted file mode 100644 index 852bce8b9f39..000000000000 --- a/internal/terraform/testdata/apply-module-provider-close-nested/child/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -module "subchild" { - source = "./subchild" -} diff --git a/internal/terraform/testdata/apply-module-provider-close-nested/child/subchild/main.tf b/internal/terraform/testdata/apply-module-provider-close-nested/child/subchild/main.tf deleted file mode 100644 index 919f140bba6b..000000000000 --- a/internal/terraform/testdata/apply-module-provider-close-nested/child/subchild/main.tf +++ /dev/null @@ -1 +0,0 @@ -resource "aws_instance" "foo" {} diff --git a/internal/terraform/testdata/apply-module-provider-close-nested/main.tf b/internal/terraform/testdata/apply-module-provider-close-nested/main.tf deleted file mode 100644 index 0f6991c536ca..000000000000 --- a/internal/terraform/testdata/apply-module-provider-close-nested/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -module "child" { - source = "./child" -} diff --git a/internal/terraform/testdata/apply-module-provider-inherit-alias-orphan/main.tf b/internal/terraform/testdata/apply-module-provider-inherit-alias-orphan/main.tf deleted file mode 100644 index 4332b9adb723..000000000000 --- a/internal/terraform/testdata/apply-module-provider-inherit-alias-orphan/main.tf +++ /dev/null @@ -1,6 +0,0 @@ -provider "aws" { -} - -provider "aws" { - alias = "eu" -} diff --git a/internal/terraform/testdata/apply-module-provider-inherit-alias/child/main.tf b/internal/terraform/testdata/apply-module-provider-inherit-alias/child/main.tf deleted file mode 100644 index 2db7c4ee88b6..000000000000 --- a/internal/terraform/testdata/apply-module-provider-inherit-alias/child/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -provider "aws" { - alias = "eu" -} - -resource "aws_instance" "foo" { - provider = "aws.eu" -} diff --git a/internal/terraform/testdata/apply-module-provider-inherit-alias/main.tf b/internal/terraform/testdata/apply-module-provider-inherit-alias/main.tf deleted file mode 100644 index a018d1468f13..000000000000 --- a/internal/terraform/testdata/apply-module-provider-inherit-alias/main.tf +++ /dev/null @@ -1,15 +0,0 @@ -provider "aws" { - root = 1 -} - -provider "aws" { - value = "eu" - alias = "eu" -} - -module "child" { - source = "./child" - providers = { - "aws.eu" = "aws.eu" - } -} diff --git a/internal/terraform/testdata/apply-module-replace-cycle-cbd/main.tf b/internal/terraform/testdata/apply-module-replace-cycle-cbd/main.tf deleted file mode 100644 index 6393231d6858..000000000000 --- a/internal/terraform/testdata/apply-module-replace-cycle-cbd/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -module "a" { - source = "./mod1" -} - -module "b" { - source = "./mod2" - ids = module.a.ids -} diff --git a/internal/terraform/testdata/apply-module-replace-cycle-cbd/mod1/main.tf b/internal/terraform/testdata/apply-module-replace-cycle-cbd/mod1/main.tf deleted file mode 100644 index 2ade442bfd3f..000000000000 --- a/internal/terraform/testdata/apply-module-replace-cycle-cbd/mod1/main.tf +++ /dev/null @@ -1,10 +0,0 @@ -resource "aws_instance" "a" { - require_new = "new" - lifecycle { - create_before_destroy = true - } -} - -output "ids" { - value = [aws_instance.a.id] -} diff --git a/internal/terraform/testdata/apply-module-replace-cycle-cbd/mod2/main.tf b/internal/terraform/testdata/apply-module-replace-cycle-cbd/mod2/main.tf deleted file mode 100644 index 83fb1dcd467b..000000000000 --- a/internal/terraform/testdata/apply-module-replace-cycle-cbd/mod2/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -resource "aws_instance" "b" { - count = length(var.ids) - require_new = var.ids[count.index] -} - -variable "ids" { - type = list(string) -} diff --git a/internal/terraform/testdata/apply-module-replace-cycle/main.tf b/internal/terraform/testdata/apply-module-replace-cycle/main.tf deleted file mode 100644 index 6393231d6858..000000000000 --- a/internal/terraform/testdata/apply-module-replace-cycle/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -module "a" { - source = "./mod1" -} - -module "b" { - source = "./mod2" - ids = module.a.ids -} diff --git a/internal/terraform/testdata/apply-module-replace-cycle/mod1/main.tf b/internal/terraform/testdata/apply-module-replace-cycle/mod1/main.tf deleted file mode 100644 index 3dd26cb8e7e8..000000000000 --- a/internal/terraform/testdata/apply-module-replace-cycle/mod1/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "a" { - require_new = "new" -} - -output "ids" { - value = [aws_instance.a.id] -} diff --git a/internal/terraform/testdata/apply-module-replace-cycle/mod2/main.tf b/internal/terraform/testdata/apply-module-replace-cycle/mod2/main.tf deleted file mode 100644 index 83fb1dcd467b..000000000000 --- a/internal/terraform/testdata/apply-module-replace-cycle/mod2/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -resource "aws_instance" "b" { - count = length(var.ids) - require_new = var.ids[count.index] -} - -variable "ids" { - type = list(string) -} diff --git a/internal/terraform/testdata/apply-module-var-resource-count/child/main.tf b/internal/terraform/testdata/apply-module-var-resource-count/child/main.tf deleted file mode 100644 index 1a19910e8f34..000000000000 --- a/internal/terraform/testdata/apply-module-var-resource-count/child/main.tf +++ /dev/null @@ -1,6 +0,0 @@ -variable "num" { -} - -resource "aws_instance" "foo" { - count = "${var.num}" -} diff --git a/internal/terraform/testdata/apply-module-var-resource-count/main.tf b/internal/terraform/testdata/apply-module-var-resource-count/main.tf deleted file mode 100644 index 6f7d20c48bf7..000000000000 --- a/internal/terraform/testdata/apply-module-var-resource-count/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -variable "num" { -} - -module "child" { - source = "./child" - num = "${var.num}" -} diff --git a/internal/terraform/testdata/apply-module/child/main.tf b/internal/terraform/testdata/apply-module/child/main.tf deleted file mode 100644 index f279d9b80bff..000000000000 --- a/internal/terraform/testdata/apply-module/child/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_instance" "baz" { - foo = "bar" -} diff --git a/internal/terraform/testdata/apply-module/main.tf b/internal/terraform/testdata/apply-module/main.tf deleted file mode 100644 index f9119a109eb4..000000000000 --- a/internal/terraform/testdata/apply-module/main.tf +++ /dev/null @@ -1,11 +0,0 @@ -module "child" { - source = "./child" -} - -resource "aws_instance" "foo" { - num = "2" -} - -resource "aws_instance" "bar" { - foo = "bar" -} diff --git a/internal/terraform/testdata/apply-multi-depose-create-before-destroy/main.tf b/internal/terraform/testdata/apply-multi-depose-create-before-destroy/main.tf deleted file mode 100644 index e5a723b3a495..000000000000 --- a/internal/terraform/testdata/apply-multi-depose-create-before-destroy/main.tf +++ /dev/null @@ -1,12 +0,0 @@ -variable "require_new" { - type = string -} - -resource "aws_instance" "web" { - // require_new is a special attribute recognized by testDiffFn that forces - // a new resource on every apply - require_new = var.require_new - lifecycle { - create_before_destroy = true - } -} diff --git a/internal/terraform/testdata/apply-multi-provider-destroy-child/child/main.tf b/internal/terraform/testdata/apply-multi-provider-destroy-child/child/main.tf deleted file mode 100644 index ae1bc8ee4c25..000000000000 --- a/internal/terraform/testdata/apply-multi-provider-destroy-child/child/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_instance" "bar" { - foo = "bar" -} diff --git a/internal/terraform/testdata/apply-multi-provider-destroy-child/main.tf b/internal/terraform/testdata/apply-multi-provider-destroy-child/main.tf deleted file mode 100644 index 9b799979b139..000000000000 --- a/internal/terraform/testdata/apply-multi-provider-destroy-child/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -resource "vault_instance" "foo" {} - -provider "aws" { - value = "${vault_instance.foo.id}" -} - -module "child" { - source = "./child" -} diff --git a/internal/terraform/testdata/apply-multi-provider-destroy/main.tf b/internal/terraform/testdata/apply-multi-provider-destroy/main.tf deleted file mode 100644 index dd3041bb5d4b..000000000000 --- a/internal/terraform/testdata/apply-multi-provider-destroy/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -resource "vault_instance" "foo" {} - -provider "aws" { - addr = "${vault_instance.foo.id}" -} - -resource "aws_instance" "bar" { - foo = "bar" -} diff --git a/internal/terraform/testdata/apply-multi-provider/main.tf b/internal/terraform/testdata/apply-multi-provider/main.tf deleted file mode 100644 index 4ee94a3bfe6d..000000000000 --- a/internal/terraform/testdata/apply-multi-provider/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "do_instance" "foo" { - num = "2" -} - -resource "aws_instance" "bar" { - foo = "bar" -} diff --git a/internal/terraform/testdata/apply-multi-ref/main.tf b/internal/terraform/testdata/apply-multi-ref/main.tf deleted file mode 100644 index 2a6a67152179..000000000000 --- a/internal/terraform/testdata/apply-multi-ref/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -resource "aws_instance" "create" { - bar = "abc" -} - -resource "aws_instance" "other" { - var = "${aws_instance.create.id}" - foo = "${aws_instance.create.bar}" -} diff --git a/internal/terraform/testdata/apply-multi-var-comprehensive/child/child.tf b/internal/terraform/testdata/apply-multi-var-comprehensive/child/child.tf deleted file mode 100644 index 8fe7df7c232e..000000000000 --- a/internal/terraform/testdata/apply-multi-var-comprehensive/child/child.tf +++ /dev/null @@ -1,29 +0,0 @@ -variable "num" { -} - -variable "source_ids" { - type = list(string) -} - -variable "source_names" { - type = list(string) -} - -resource "test_thing" "multi_count_var" { - count = var.num - - key = "child.multi_count_var.${count.index}" - - # Can pluck a single item out of a multi-var - source_id = var.source_ids[count.index] -} - -resource "test_thing" "whole_splat" { - key = "child.whole_splat" - - # Can "splat" the ids directly into an attribute of type list. - source_ids = var.source_ids - source_names = var.source_names - source_ids_wrapped = ["${var.source_ids}"] - source_names_wrapped = ["${var.source_names}"] -} diff --git a/internal/terraform/testdata/apply-multi-var-comprehensive/root.tf b/internal/terraform/testdata/apply-multi-var-comprehensive/root.tf deleted file mode 100644 index 64ada6be6f22..000000000000 --- a/internal/terraform/testdata/apply-multi-var-comprehensive/root.tf +++ /dev/null @@ -1,74 +0,0 @@ -variable "num" { -} - -resource "test_thing" "source" { - count = var.num - - key = "source.${count.index}" - - # The diffFunc in the test exports "name" here too, which we can use - # to test values that are known during plan. -} - -resource "test_thing" "multi_count_var" { - count = var.num - - key = "multi_count_var.${count.index}" - - # Can pluck a single item out of a multi-var - source_id = test_thing.source.*.id[count.index] - source_name = test_thing.source.*.name[count.index] -} - -resource "test_thing" "multi_count_derived" { - # Can use the source to get the count - count = length(test_thing.source) - - key = "multi_count_derived.${count.index}" - - source_id = test_thing.source.*.id[count.index] - source_name = test_thing.source.*.name[count.index] -} - -resource "test_thing" "whole_splat" { - key = "whole_splat" - - # Can "splat" the ids directly into an attribute of type list. - source_ids = test_thing.source.*.id - source_names = test_thing.source.*.name - - # Accessing through a function should work. - source_ids_from_func = split(" ", join(" ", test_thing.source.*.id)) - source_names_from_func = split(" ", join(" ", test_thing.source.*.name)) - - # A common pattern of selecting with a default. - first_source_id = element(concat(test_thing.source.*.id, ["default"]), 0) - first_source_name = element(concat(test_thing.source.*.name, ["default"]), 0) - - # Prior to v0.12 we were handling lists containing list interpolations as - # a special case, flattening the result, for compatibility with behavior - # prior to v0.10. This deprecated handling is now removed, and so these - # each produce a list of lists. We're still using the interpolation syntax - # here, rather than the splat expression directly, to properly mimic how - # this would've looked prior to v0.12 to be explicit about what the new - # behavior is for this old syntax. - source_ids_wrapped = ["${test_thing.source.*.id}"] - source_names_wrapped = ["${test_thing.source.*.name}"] - -} - -module "child" { - source = "./child" - - num = var.num - source_ids = test_thing.source.*.id - source_names = test_thing.source.*.name -} - -output "source_ids" { - value = test_thing.source.*.id -} - -output "source_names" { - value = test_thing.source.*.name -} diff --git a/internal/terraform/testdata/apply-multi-var-count-dec/main.tf b/internal/terraform/testdata/apply-multi-var-count-dec/main.tf deleted file mode 100644 index 40476512fa09..000000000000 --- a/internal/terraform/testdata/apply-multi-var-count-dec/main.tf +++ /dev/null @@ -1,12 +0,0 @@ -variable "num" {} - -resource "aws_instance" "foo" { - count = "${var.num}" - value = "foo" -} - -resource "aws_instance" "bar" { - ami = "special" - - value = "${join(",", aws_instance.foo.*.id)}" -} diff --git a/internal/terraform/testdata/apply-multi-var-missing-state/child/child.tf b/internal/terraform/testdata/apply-multi-var-missing-state/child/child.tf deleted file mode 100644 index b5df05d0e247..000000000000 --- a/internal/terraform/testdata/apply-multi-var-missing-state/child/child.tf +++ /dev/null @@ -1,15 +0,0 @@ - -# This resource gets visited first on the apply walk, but since it DynamicExpands -# to an empty subgraph it ends up being a no-op, leaving the module state -# uninitialized. -resource "test_thing" "a" { - count = 0 -} - -# This resource is visited second. During its eval walk we try to build the -# array for the null_resource.a.*.id interpolation, which involves iterating -# over all of the resource in the state. This should succeed even though the -# module state will be nil when evaluating the variable. -resource "test_thing" "b" { - a_ids = "${join(" ", test_thing.a.*.id)}" -} diff --git a/internal/terraform/testdata/apply-multi-var-missing-state/root.tf b/internal/terraform/testdata/apply-multi-var-missing-state/root.tf deleted file mode 100644 index 25a0a1f9b49e..000000000000 --- a/internal/terraform/testdata/apply-multi-var-missing-state/root.tf +++ /dev/null @@ -1,7 +0,0 @@ -// We test this in a child module, since the root module state exists -// very early on, even before any resources are created in it, but that is not -// true for child modules. - -module "child" { - source = "./child" -} diff --git a/internal/terraform/testdata/apply-multi-var-order-interp/main.tf b/internal/terraform/testdata/apply-multi-var-order-interp/main.tf deleted file mode 100644 index 6cc2e29d9add..000000000000 --- a/internal/terraform/testdata/apply-multi-var-order-interp/main.tf +++ /dev/null @@ -1,17 +0,0 @@ -variable "num" { - default = 15 -} - -resource "aws_instance" "bar" { - count = "${var.num}" - foo = "index-${count.index}" -} - -resource "aws_instance" "baz" { - count = "${var.num}" - foo = "baz-${element(aws_instance.bar.*.foo, count.index)}" -} - -output "should-be-11" { - value = "${element(aws_instance.baz.*.foo, 11)}" -} diff --git a/internal/terraform/testdata/apply-multi-var-order/main.tf b/internal/terraform/testdata/apply-multi-var-order/main.tf deleted file mode 100644 index 7ffefb6f349b..000000000000 --- a/internal/terraform/testdata/apply-multi-var-order/main.tf +++ /dev/null @@ -1,12 +0,0 @@ -variable "num" { - default = 15 -} - -resource "aws_instance" "bar" { - count = "${var.num}" - foo = "index-${count.index}" -} - -output "should-be-11" { - value = "${element(aws_instance.bar.*.foo, 11)}" -} diff --git a/internal/terraform/testdata/apply-multi-var/main.tf b/internal/terraform/testdata/apply-multi-var/main.tf deleted file mode 100644 index c7ed45c6a816..000000000000 --- a/internal/terraform/testdata/apply-multi-var/main.tf +++ /dev/null @@ -1,10 +0,0 @@ -variable "num" {} - -resource "aws_instance" "bar" { - count = "${var.num}" - foo = "bar${count.index}" -} - -output "output" { - value = "${join(",", aws_instance.bar.*.foo)}" -} diff --git a/internal/terraform/testdata/apply-nullable-variables/main.tf b/internal/terraform/testdata/apply-nullable-variables/main.tf deleted file mode 100644 index ed4b6c7f26f2..000000000000 --- a/internal/terraform/testdata/apply-nullable-variables/main.tf +++ /dev/null @@ -1,28 +0,0 @@ -module "mod" { - source = "./mod" - nullable_null_default = null - nullable_non_null_default = null - nullable_no_default = null - non_nullable_default = null - non_nullable_no_default = "ok" -} - -output "nullable_null_default" { - value = module.mod.nullable_null_default -} - -output "nullable_non_null_default" { - value = module.mod.nullable_non_null_default -} - -output "nullable_no_default" { - value = module.mod.nullable_no_default -} - -output "non_nullable_default" { - value = module.mod.non_nullable_default -} - -output "non_nullable_no_default" { - value = module.mod.non_nullable_no_default -} diff --git a/internal/terraform/testdata/apply-nullable-variables/mod/main.tf b/internal/terraform/testdata/apply-nullable-variables/mod/main.tf deleted file mode 100644 index fcac3ba37260..000000000000 --- a/internal/terraform/testdata/apply-nullable-variables/mod/main.tf +++ /dev/null @@ -1,59 +0,0 @@ -// optional, and this can take null as an input -variable "nullable_null_default" { - // This is implied now as the default, and probably should be implied even - // when nullable=false is the default, so we're leaving this unset for the test. - // nullable = true - - default = null -} - -// assigning null can still override the default. -variable "nullable_non_null_default" { - nullable = true - default = "ok" -} - -// required, and assigning null is valid. -variable "nullable_no_default" { - nullable = true -} - - -// this combination is invalid -//variable "non_nullable_null_default" { -// nullable = false -// default = null -//} - - -// assigning null will take the default -variable "non_nullable_default" { - nullable = false - default = "ok" -} - -// required, but null is not a valid value -variable "non_nullable_no_default" { - nullable = false -} - -output "nullable_null_default" { - value = var.nullable_null_default -} - -output "nullable_non_null_default" { - value = var.nullable_non_null_default -} - -output "nullable_no_default" { - value = var.nullable_no_default -} - -output "non_nullable_default" { - value = var.non_nullable_default -} - -output "non_nullable_no_default" { - value = var.non_nullable_no_default -} - diff --git a/internal/terraform/testdata/apply-orphan-resource/main.tf b/internal/terraform/testdata/apply-orphan-resource/main.tf deleted file mode 100644 index 3e093ac83f50..000000000000 --- a/internal/terraform/testdata/apply-orphan-resource/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "test_thing" "zero" { - count = 0 -} - -resource "test_thing" "one" { - count = 1 -} diff --git a/internal/terraform/testdata/apply-output-add-after/main.tf b/internal/terraform/testdata/apply-output-add-after/main.tf deleted file mode 100644 index 1c10eaafc571..000000000000 --- a/internal/terraform/testdata/apply-output-add-after/main.tf +++ /dev/null @@ -1,6 +0,0 @@ -provider "aws" {} - -resource "aws_instance" "test" { - foo = "${format("foo%d", count.index)}" - count = 2 -} diff --git a/internal/terraform/testdata/apply-output-add-after/outputs.tf.json b/internal/terraform/testdata/apply-output-add-after/outputs.tf.json deleted file mode 100644 index 32e96b0ee07c..000000000000 --- a/internal/terraform/testdata/apply-output-add-after/outputs.tf.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "output": { - "firstOutput": { - "value": "${aws_instance.test.0.foo}" - }, - "secondOutput": { - "value": "${aws_instance.test.1.foo}" - } - } -} diff --git a/internal/terraform/testdata/apply-output-add-before/main.tf b/internal/terraform/testdata/apply-output-add-before/main.tf deleted file mode 100644 index 1c10eaafc571..000000000000 --- a/internal/terraform/testdata/apply-output-add-before/main.tf +++ /dev/null @@ -1,6 +0,0 @@ -provider "aws" {} - -resource "aws_instance" "test" { - foo = "${format("foo%d", count.index)}" - count = 2 -} diff --git a/internal/terraform/testdata/apply-output-add-before/outputs.tf.json b/internal/terraform/testdata/apply-output-add-before/outputs.tf.json deleted file mode 100644 index 238668ef3d17..000000000000 --- a/internal/terraform/testdata/apply-output-add-before/outputs.tf.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "output": { - "firstOutput": { - "value": "${aws_instance.test.0.foo}" - } - } -} diff --git a/internal/terraform/testdata/apply-output-list/main.tf b/internal/terraform/testdata/apply-output-list/main.tf deleted file mode 100644 index 11b8107dffd4..000000000000 --- a/internal/terraform/testdata/apply-output-list/main.tf +++ /dev/null @@ -1,12 +0,0 @@ -resource "aws_instance" "foo" { - num = "2" -} - -resource "aws_instance" "bar" { - foo = "bar" - count = 3 -} - -output "foo_num" { - value = ["${join(",", aws_instance.bar.*.foo)}"] -} diff --git a/internal/terraform/testdata/apply-output-multi-index/main.tf b/internal/terraform/testdata/apply-output-multi-index/main.tf deleted file mode 100644 index c7ede94d5a83..000000000000 --- a/internal/terraform/testdata/apply-output-multi-index/main.tf +++ /dev/null @@ -1,12 +0,0 @@ -resource "aws_instance" "foo" { - num = "2" -} - -resource "aws_instance" "bar" { - foo = "bar" - count = 3 -} - -output "foo_num" { - value = "${aws_instance.bar.0.foo}" -} diff --git a/internal/terraform/testdata/apply-output-multi/main.tf b/internal/terraform/testdata/apply-output-multi/main.tf deleted file mode 100644 index a70e334b16be..000000000000 --- a/internal/terraform/testdata/apply-output-multi/main.tf +++ /dev/null @@ -1,12 +0,0 @@ -resource "aws_instance" "foo" { - num = "2" -} - -resource "aws_instance" "bar" { - foo = "bar" - count = 3 -} - -output "foo_num" { - value = "${join(",", aws_instance.bar.*.foo)}" -} diff --git a/internal/terraform/testdata/apply-output-orphan-module/child/main.tf b/internal/terraform/testdata/apply-output-orphan-module/child/main.tf deleted file mode 100644 index ae32f8aa13b3..000000000000 --- a/internal/terraform/testdata/apply-output-orphan-module/child/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -output "foo" { - value = "bar" -} diff --git a/internal/terraform/testdata/apply-output-orphan-module/main.tf b/internal/terraform/testdata/apply-output-orphan-module/main.tf deleted file mode 100644 index 0f6991c536ca..000000000000 --- a/internal/terraform/testdata/apply-output-orphan-module/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -module "child" { - source = "./child" -} diff --git a/internal/terraform/testdata/apply-output-orphan/main.tf b/internal/terraform/testdata/apply-output-orphan/main.tf deleted file mode 100644 index ae32f8aa13b3..000000000000 --- a/internal/terraform/testdata/apply-output-orphan/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -output "foo" { - value = "bar" -} diff --git a/internal/terraform/testdata/apply-output/main.tf b/internal/terraform/testdata/apply-output/main.tf deleted file mode 100644 index 1f91a40f150e..000000000000 --- a/internal/terraform/testdata/apply-output/main.tf +++ /dev/null @@ -1,11 +0,0 @@ -resource "aws_instance" "foo" { - num = "2" -} - -resource "aws_instance" "bar" { - foo = "bar" -} - -output "foo_num" { - value = "${aws_instance.foo.num}" -} diff --git a/internal/terraform/testdata/apply-plan-connection-refs/main.tf b/internal/terraform/testdata/apply-plan-connection-refs/main.tf deleted file mode 100644 index d20191f33b13..000000000000 --- a/internal/terraform/testdata/apply-plan-connection-refs/main.tf +++ /dev/null @@ -1,18 +0,0 @@ -variable "msg" { - default = "ok" -} - -resource "test_instance" "a" { - foo = "a" -} - - -resource "test_instance" "b" { - foo = "b" - provisioner "shell" { - command = "echo ${var.msg}" - } - connection { - host = test_instance.a.id - } -} diff --git a/internal/terraform/testdata/apply-provider-alias-configure/main.tf b/internal/terraform/testdata/apply-provider-alias-configure/main.tf deleted file mode 100644 index 4487e4573ab3..000000000000 --- a/internal/terraform/testdata/apply-provider-alias-configure/main.tf +++ /dev/null @@ -1,14 +0,0 @@ -provider "another" { - foo = "bar" -} - -provider "another" { - alias = "two" - foo = "bar" -} - -resource "another_instance" "foo" {} - -resource "another_instance" "bar" { - provider = "another.two" -} diff --git a/internal/terraform/testdata/apply-provider-alias/main.tf b/internal/terraform/testdata/apply-provider-alias/main.tf deleted file mode 100644 index 19fd985abf2c..000000000000 --- a/internal/terraform/testdata/apply-provider-alias/main.tf +++ /dev/null @@ -1,12 +0,0 @@ -provider "aws" { - alias = "bar" -} - -resource "aws_instance" "foo" { - num = "2" -} - -resource "aws_instance" "bar" { - foo = "bar" - provider = "aws.bar" -} diff --git a/internal/terraform/testdata/apply-provider-computed/main.tf b/internal/terraform/testdata/apply-provider-computed/main.tf deleted file mode 100644 index 81acf7cfaa9d..000000000000 --- a/internal/terraform/testdata/apply-provider-computed/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -provider "aws" { - value = test_instance.foo.id -} - -resource "aws_instance" "bar" {} - -resource "test_instance" "foo" { - value = "yes" -} diff --git a/internal/terraform/testdata/apply-provider-configure-disabled/child/main.tf b/internal/terraform/testdata/apply-provider-configure-disabled/child/main.tf deleted file mode 100644 index c421bf743c30..000000000000 --- a/internal/terraform/testdata/apply-provider-configure-disabled/child/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -provider "aws" { - value = "foo" -} - -resource "aws_instance" "foo" {} diff --git a/internal/terraform/testdata/apply-provider-configure-disabled/main.tf b/internal/terraform/testdata/apply-provider-configure-disabled/main.tf deleted file mode 100644 index dbfc52745d69..000000000000 --- a/internal/terraform/testdata/apply-provider-configure-disabled/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -provider "aws" { - foo = "bar" -} - -module "child" { - source = "./child" -} diff --git a/internal/terraform/testdata/apply-provider-warning/main.tf b/internal/terraform/testdata/apply-provider-warning/main.tf deleted file mode 100644 index 919f140bba6b..000000000000 --- a/internal/terraform/testdata/apply-provider-warning/main.tf +++ /dev/null @@ -1 +0,0 @@ -resource "aws_instance" "foo" {} diff --git a/internal/terraform/testdata/apply-provisioner-compute/main.tf b/internal/terraform/testdata/apply-provisioner-compute/main.tf deleted file mode 100644 index 598296501d00..000000000000 --- a/internal/terraform/testdata/apply-provisioner-compute/main.tf +++ /dev/null @@ -1,13 +0,0 @@ -variable "value" {} - -resource "aws_instance" "foo" { - num = "2" - compute = "value" - compute_value = "${var.value}" -} - -resource "aws_instance" "bar" { - provisioner "shell" { - command = "${aws_instance.foo.value}" - } -} diff --git a/internal/terraform/testdata/apply-provisioner-destroy-continue/main.tf b/internal/terraform/testdata/apply-provisioner-destroy-continue/main.tf deleted file mode 100644 index 0be0d331e51b..000000000000 --- a/internal/terraform/testdata/apply-provisioner-destroy-continue/main.tf +++ /dev/null @@ -1,15 +0,0 @@ -resource "aws_instance" "foo" { - foo = "bar" - - provisioner "shell" { - command = "one" - when = "destroy" - on_failure = "continue" - } - - provisioner "shell" { - command = "two" - when = "destroy" - on_failure = "continue" - } -} diff --git a/internal/terraform/testdata/apply-provisioner-destroy-fail/main.tf b/internal/terraform/testdata/apply-provisioner-destroy-fail/main.tf deleted file mode 100644 index 14ad1258293d..000000000000 --- a/internal/terraform/testdata/apply-provisioner-destroy-fail/main.tf +++ /dev/null @@ -1,14 +0,0 @@ -resource "aws_instance" "foo" { - foo = "bar" - - provisioner "shell" { - command = "one" - when = "destroy" - on_failure = "continue" - } - - provisioner "shell" { - command = "two" - when = "destroy" - } -} diff --git a/internal/terraform/testdata/apply-provisioner-destroy/main.tf b/internal/terraform/testdata/apply-provisioner-destroy/main.tf deleted file mode 100644 index 8804f6495245..000000000000 --- a/internal/terraform/testdata/apply-provisioner-destroy/main.tf +++ /dev/null @@ -1,18 +0,0 @@ -resource "aws_instance" "foo" { - for_each = var.input - foo = "bar" - - provisioner "shell" { - command = "create ${each.key} ${each.value}" - } - - provisioner "shell" { - when = "destroy" - command = "destroy ${each.key} ${self.foo}" - } -} - -variable "input" { - type = map(string) - default = {} -} diff --git a/internal/terraform/testdata/apply-provisioner-diff/main.tf b/internal/terraform/testdata/apply-provisioner-diff/main.tf deleted file mode 100644 index ac4f38e97a9c..000000000000 --- a/internal/terraform/testdata/apply-provisioner-diff/main.tf +++ /dev/null @@ -1,4 +0,0 @@ -resource "aws_instance" "bar" { - foo = "bar" - provisioner "shell" {} -} diff --git a/internal/terraform/testdata/apply-provisioner-explicit-self-ref/main.tf b/internal/terraform/testdata/apply-provisioner-explicit-self-ref/main.tf deleted file mode 100644 index 7ceca47db81c..000000000000 --- a/internal/terraform/testdata/apply-provisioner-explicit-self-ref/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "foo" { - foo = "bar" - - provisioner "shell" { - command = "${aws_instance.foo.foo}" - } -} diff --git a/internal/terraform/testdata/apply-provisioner-fail-continue/main.tf b/internal/terraform/testdata/apply-provisioner-fail-continue/main.tf deleted file mode 100644 index 39587984e66c..000000000000 --- a/internal/terraform/testdata/apply-provisioner-fail-continue/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "foo" { - foo = "bar" - - provisioner "shell" { - on_failure = "continue" - } -} diff --git a/internal/terraform/testdata/apply-provisioner-fail-create-before/main.tf b/internal/terraform/testdata/apply-provisioner-fail-create-before/main.tf deleted file mode 100644 index 00d32cbc24f8..000000000000 --- a/internal/terraform/testdata/apply-provisioner-fail-create-before/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "bar" { - require_new = "xyz" - provisioner "shell" {} - lifecycle { - create_before_destroy = true - } -} diff --git a/internal/terraform/testdata/apply-provisioner-fail-create/main.tf b/internal/terraform/testdata/apply-provisioner-fail-create/main.tf deleted file mode 100644 index c1dcd222c0b1..000000000000 --- a/internal/terraform/testdata/apply-provisioner-fail-create/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_instance" "bar" { - provisioner "shell" {} -} diff --git a/internal/terraform/testdata/apply-provisioner-fail/main.tf b/internal/terraform/testdata/apply-provisioner-fail/main.tf deleted file mode 100644 index 4aacf4b5b16e..000000000000 --- a/internal/terraform/testdata/apply-provisioner-fail/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "foo" { - num = "2" -} - -resource "aws_instance" "bar" { - provisioner "shell" {} -} diff --git a/internal/terraform/testdata/apply-provisioner-for-each-self/main.tf b/internal/terraform/testdata/apply-provisioner-for-each-self/main.tf deleted file mode 100644 index f3e1d58df260..000000000000 --- a/internal/terraform/testdata/apply-provisioner-for-each-self/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -resource "aws_instance" "foo" { - for_each = toset(["a", "b", "c"]) - foo = "number ${each.value}" - - provisioner "shell" { - command = "${self.foo}" - } -} diff --git a/internal/terraform/testdata/apply-provisioner-interp-count/provisioner-interp-count.tf b/internal/terraform/testdata/apply-provisioner-interp-count/provisioner-interp-count.tf deleted file mode 100644 index 337129e61b08..000000000000 --- a/internal/terraform/testdata/apply-provisioner-interp-count/provisioner-interp-count.tf +++ /dev/null @@ -1,17 +0,0 @@ -variable "num" { - default = 3 -} - -resource "aws_instance" "a" { - count = var.num -} - -resource "aws_instance" "b" { - provisioner "local-exec" { - # Since we're in a provisioner block here, this expression is - # resolved during the apply walk and so the resource count must - # be known during that walk, even though apply walk doesn't - # do DynamicExpand. - command = "echo ${length(aws_instance.a)}" - } -} diff --git a/internal/terraform/testdata/apply-provisioner-module/child/main.tf b/internal/terraform/testdata/apply-provisioner-module/child/main.tf deleted file mode 100644 index 85b58ff94dc1..000000000000 --- a/internal/terraform/testdata/apply-provisioner-module/child/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -resource "aws_instance" "bar" { - provisioner "shell" { - foo = "bar" - } -} diff --git a/internal/terraform/testdata/apply-provisioner-module/main.tf b/internal/terraform/testdata/apply-provisioner-module/main.tf deleted file mode 100644 index 1f95749fa7ea..000000000000 --- a/internal/terraform/testdata/apply-provisioner-module/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -module "child" { - source = "./child" -} diff --git a/internal/terraform/testdata/apply-provisioner-multi-self-ref-single/main.tf b/internal/terraform/testdata/apply-provisioner-multi-self-ref-single/main.tf deleted file mode 100644 index d6c995115ea9..000000000000 --- a/internal/terraform/testdata/apply-provisioner-multi-self-ref-single/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -resource "aws_instance" "foo" { - count = 3 - foo = "number ${count.index}" - - provisioner "shell" { - command = aws_instance.foo[0].foo - order = count.index - } -} diff --git a/internal/terraform/testdata/apply-provisioner-multi-self-ref/main.tf b/internal/terraform/testdata/apply-provisioner-multi-self-ref/main.tf deleted file mode 100644 index 72a1e7920076..000000000000 --- a/internal/terraform/testdata/apply-provisioner-multi-self-ref/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -resource "aws_instance" "foo" { - count = 3 - foo = "number ${count.index}" - - provisioner "shell" { - command = "${self.foo}" - } -} diff --git a/internal/terraform/testdata/apply-provisioner-resource-ref/main.tf b/internal/terraform/testdata/apply-provisioner-resource-ref/main.tf deleted file mode 100644 index 25da37781cc4..000000000000 --- a/internal/terraform/testdata/apply-provisioner-resource-ref/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "bar" { - num = "2" - - provisioner "shell" { - command = "${aws_instance.bar.num}" - } -} diff --git a/internal/terraform/testdata/apply-provisioner-self-ref/main.tf b/internal/terraform/testdata/apply-provisioner-self-ref/main.tf deleted file mode 100644 index 5f401f7c07f7..000000000000 --- a/internal/terraform/testdata/apply-provisioner-self-ref/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "foo" { - foo = "bar" - - provisioner "shell" { - command = "${self.foo}" - } -} diff --git a/internal/terraform/testdata/apply-provisioner-sensitive/main.tf b/internal/terraform/testdata/apply-provisioner-sensitive/main.tf deleted file mode 100644 index 99ec4a290b78..000000000000 --- a/internal/terraform/testdata/apply-provisioner-sensitive/main.tf +++ /dev/null @@ -1,18 +0,0 @@ -variable "password" { - type = string - sensitive = true -} - -resource "aws_instance" "foo" { - connection { - host = "localhost" - type = "telnet" - user = "superuser" - port = 2222 - password = var.password - } - - provisioner "shell" { - command = "echo ${var.password} > secrets" - } -} diff --git a/internal/terraform/testdata/apply-ref-count/main.tf b/internal/terraform/testdata/apply-ref-count/main.tf deleted file mode 100644 index 1ce2ffe21f5d..000000000000 --- a/internal/terraform/testdata/apply-ref-count/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "foo" { - count = 3 -} - -resource "aws_instance" "bar" { - foo = length(aws_instance.foo) -} diff --git a/internal/terraform/testdata/apply-ref-existing/child/main.tf b/internal/terraform/testdata/apply-ref-existing/child/main.tf deleted file mode 100644 index cd1e56eec90e..000000000000 --- a/internal/terraform/testdata/apply-ref-existing/child/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -variable "var" {} - -resource "aws_instance" "foo" { - value = "${var.var}" -} diff --git a/internal/terraform/testdata/apply-ref-existing/main.tf b/internal/terraform/testdata/apply-ref-existing/main.tf deleted file mode 100644 index a05056c52e54..000000000000 --- a/internal/terraform/testdata/apply-ref-existing/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -resource "aws_instance" "foo" { - foo = "bar" -} - -module "child" { - source = "./child" - - var = "${aws_instance.foo.foo}" -} diff --git a/internal/terraform/testdata/apply-resource-count-one-list/main.tf b/internal/terraform/testdata/apply-resource-count-one-list/main.tf deleted file mode 100644 index 0aeb75b1afa9..000000000000 --- a/internal/terraform/testdata/apply-resource-count-one-list/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "null_resource" "foo" { - count = 1 -} - -output "test" { - value = "${sort(null_resource.foo.*.id)}" -} diff --git a/internal/terraform/testdata/apply-resource-count-zero-list/main.tf b/internal/terraform/testdata/apply-resource-count-zero-list/main.tf deleted file mode 100644 index 6d9b4d55d286..000000000000 --- a/internal/terraform/testdata/apply-resource-count-zero-list/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "null_resource" "foo" { - count = 0 -} - -output "test" { - value = "${sort(null_resource.foo.*.id)}" -} diff --git a/internal/terraform/testdata/apply-resource-depends-on-module-deep/child/child/main.tf b/internal/terraform/testdata/apply-resource-depends-on-module-deep/child/child/main.tf deleted file mode 100644 index 77203263df45..000000000000 --- a/internal/terraform/testdata/apply-resource-depends-on-module-deep/child/child/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_instance" "c" { - ami = "grandchild" -} diff --git a/internal/terraform/testdata/apply-resource-depends-on-module-deep/child/main.tf b/internal/terraform/testdata/apply-resource-depends-on-module-deep/child/main.tf deleted file mode 100644 index 6cbe350a7958..000000000000 --- a/internal/terraform/testdata/apply-resource-depends-on-module-deep/child/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -module "grandchild" { - source = "./child" -} diff --git a/internal/terraform/testdata/apply-resource-depends-on-module-deep/main.tf b/internal/terraform/testdata/apply-resource-depends-on-module-deep/main.tf deleted file mode 100644 index 1a7862b0a3f0..000000000000 --- a/internal/terraform/testdata/apply-resource-depends-on-module-deep/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -module "child" { - source = "./child" -} - -resource "aws_instance" "a" { - ami = "parent" - - depends_on = ["module.child"] -} diff --git a/internal/terraform/testdata/apply-resource-depends-on-module-empty/main.tf b/internal/terraform/testdata/apply-resource-depends-on-module-empty/main.tf deleted file mode 100644 index f2316bd73ada..000000000000 --- a/internal/terraform/testdata/apply-resource-depends-on-module-empty/main.tf +++ /dev/null @@ -1 +0,0 @@ -# Empty! diff --git a/internal/terraform/testdata/apply-resource-depends-on-module-in-module/child/child/main.tf b/internal/terraform/testdata/apply-resource-depends-on-module-in-module/child/child/main.tf deleted file mode 100644 index 77203263df45..000000000000 --- a/internal/terraform/testdata/apply-resource-depends-on-module-in-module/child/child/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_instance" "c" { - ami = "grandchild" -} diff --git a/internal/terraform/testdata/apply-resource-depends-on-module-in-module/child/main.tf b/internal/terraform/testdata/apply-resource-depends-on-module-in-module/child/main.tf deleted file mode 100644 index a816cae90e5b..000000000000 --- a/internal/terraform/testdata/apply-resource-depends-on-module-in-module/child/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -module "grandchild" { - source = "./child" -} - -resource "aws_instance" "b" { - ami = "child" - depends_on = ["module.grandchild"] -} diff --git a/internal/terraform/testdata/apply-resource-depends-on-module-in-module/main.tf b/internal/terraform/testdata/apply-resource-depends-on-module-in-module/main.tf deleted file mode 100644 index 0f6991c536ca..000000000000 --- a/internal/terraform/testdata/apply-resource-depends-on-module-in-module/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -module "child" { - source = "./child" -} diff --git a/internal/terraform/testdata/apply-resource-depends-on-module/child/main.tf b/internal/terraform/testdata/apply-resource-depends-on-module/child/main.tf deleted file mode 100644 index 949d8e1b5e67..000000000000 --- a/internal/terraform/testdata/apply-resource-depends-on-module/child/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_instance" "child" { - ami = "child" -} diff --git a/internal/terraform/testdata/apply-resource-depends-on-module/main.tf b/internal/terraform/testdata/apply-resource-depends-on-module/main.tf deleted file mode 100644 index 1a7862b0a3f0..000000000000 --- a/internal/terraform/testdata/apply-resource-depends-on-module/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -module "child" { - source = "./child" -} - -resource "aws_instance" "a" { - ami = "parent" - - depends_on = ["module.child"] -} diff --git a/internal/terraform/testdata/apply-resource-scale-in/main.tf b/internal/terraform/testdata/apply-resource-scale-in/main.tf deleted file mode 100644 index 8cb38473e163..000000000000 --- a/internal/terraform/testdata/apply-resource-scale-in/main.tf +++ /dev/null @@ -1,13 +0,0 @@ -variable "instance_count" {} - -resource "aws_instance" "one" { - count = var.instance_count -} - -locals { - one_id = element(concat(aws_instance.one.*.id, [""]), 0) -} - -resource "aws_instance" "two" { - value = local.one_id -} diff --git a/internal/terraform/testdata/apply-taint-dep-requires-new/main.tf b/internal/terraform/testdata/apply-taint-dep-requires-new/main.tf deleted file mode 100644 index f964fe46e9de..000000000000 --- a/internal/terraform/testdata/apply-taint-dep-requires-new/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -resource "aws_instance" "foo" { - num = "2" -} - -resource "aws_instance" "bar" { - foo = "${aws_instance.foo.id}" - require_new = "yes" -} diff --git a/internal/terraform/testdata/apply-taint-dep/main.tf b/internal/terraform/testdata/apply-taint-dep/main.tf deleted file mode 100644 index 164db2d18ae2..000000000000 --- a/internal/terraform/testdata/apply-taint-dep/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -resource "aws_instance" "foo" { - num = "2" -} - -resource "aws_instance" "bar" { - num = "2" - foo = "${aws_instance.foo.id}" -} diff --git a/internal/terraform/testdata/apply-taint/main.tf b/internal/terraform/testdata/apply-taint/main.tf deleted file mode 100644 index 801ddbaf9b36..000000000000 --- a/internal/terraform/testdata/apply-taint/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_instance" "bar" { - num = "2" -} diff --git a/internal/terraform/testdata/apply-tainted-targets/main.tf b/internal/terraform/testdata/apply-tainted-targets/main.tf deleted file mode 100644 index 8f6b317d5bd2..000000000000 --- a/internal/terraform/testdata/apply-tainted-targets/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_instance" "ifailedprovisioners" { } - -resource "aws_instance" "iambeingadded" { } diff --git a/internal/terraform/testdata/apply-targeted-count/main.tf b/internal/terraform/testdata/apply-targeted-count/main.tf deleted file mode 100644 index cd861898f203..000000000000 --- a/internal/terraform/testdata/apply-targeted-count/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "foo" { - count = 3 -} - -resource "aws_instance" "bar" { - count = 3 -} diff --git a/internal/terraform/testdata/apply-targeted-module-dep/child/main.tf b/internal/terraform/testdata/apply-targeted-module-dep/child/main.tf deleted file mode 100644 index 90a7c407b949..000000000000 --- a/internal/terraform/testdata/apply-targeted-module-dep/child/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -resource "aws_instance" "mod" { } - -output "output" { - value = "${aws_instance.mod.id}" -} diff --git a/internal/terraform/testdata/apply-targeted-module-dep/main.tf b/internal/terraform/testdata/apply-targeted-module-dep/main.tf deleted file mode 100644 index 754219c3e3fc..000000000000 --- a/internal/terraform/testdata/apply-targeted-module-dep/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -module "child" { - source = "./child" -} - -resource "aws_instance" "foo" { - foo = "${module.child.output}" -} diff --git a/internal/terraform/testdata/apply-targeted-module-recursive/child/main.tf b/internal/terraform/testdata/apply-targeted-module-recursive/child/main.tf deleted file mode 100644 index 852bce8b9f39..000000000000 --- a/internal/terraform/testdata/apply-targeted-module-recursive/child/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -module "subchild" { - source = "./subchild" -} diff --git a/internal/terraform/testdata/apply-targeted-module-recursive/child/subchild/main.tf b/internal/terraform/testdata/apply-targeted-module-recursive/child/subchild/main.tf deleted file mode 100644 index 98f5ee87e9f0..000000000000 --- a/internal/terraform/testdata/apply-targeted-module-recursive/child/subchild/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_instance" "foo" { - num = "2" -} diff --git a/internal/terraform/testdata/apply-targeted-module-recursive/main.tf b/internal/terraform/testdata/apply-targeted-module-recursive/main.tf deleted file mode 100644 index 0f6991c536ca..000000000000 --- a/internal/terraform/testdata/apply-targeted-module-recursive/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -module "child" { - source = "./child" -} diff --git a/internal/terraform/testdata/apply-targeted-module-resource/child/main.tf b/internal/terraform/testdata/apply-targeted-module-resource/child/main.tf deleted file mode 100644 index 7872c90fcf5a..000000000000 --- a/internal/terraform/testdata/apply-targeted-module-resource/child/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "foo" { - num = "2" -} - -resource "aws_instance" "bar" { - num = "2" -} diff --git a/internal/terraform/testdata/apply-targeted-module-resource/main.tf b/internal/terraform/testdata/apply-targeted-module-resource/main.tf deleted file mode 100644 index 88bf07f6995c..000000000000 --- a/internal/terraform/testdata/apply-targeted-module-resource/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -module "child" { - source = "./child" -} - -resource "aws_instance" "bar" { - foo = "bar" -} diff --git a/internal/terraform/testdata/apply-targeted-module-unrelated-outputs/child1/main.tf b/internal/terraform/testdata/apply-targeted-module-unrelated-outputs/child1/main.tf deleted file mode 100644 index cffe3829e792..000000000000 --- a/internal/terraform/testdata/apply-targeted-module-unrelated-outputs/child1/main.tf +++ /dev/null @@ -1,17 +0,0 @@ -variable "instance_id" { -} - -output "instance_id" { - # The instance here isn't targeted, so this output shouldn't get updated. - # But it already has an existing value in state (specified within the - # test code) so we expect this to remain unchanged afterwards. - value = "${aws_instance.foo.id}" -} - -output "given_instance_id" { - value = "${var.instance_id}" -} - -resource "aws_instance" "foo" { - foo = "${var.instance_id}" -} diff --git a/internal/terraform/testdata/apply-targeted-module-unrelated-outputs/child2/main.tf b/internal/terraform/testdata/apply-targeted-module-unrelated-outputs/child2/main.tf deleted file mode 100644 index d8aa6cf3535a..000000000000 --- a/internal/terraform/testdata/apply-targeted-module-unrelated-outputs/child2/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -resource "aws_instance" "foo" { -} - -output "instance_id" { - # Even though we're targeting just the resource above, this should still - # be populated because outputs are implicitly targeted when their - # dependencies are - value = "${aws_instance.foo.id}" -} diff --git a/internal/terraform/testdata/apply-targeted-module-unrelated-outputs/main.tf b/internal/terraform/testdata/apply-targeted-module-unrelated-outputs/main.tf deleted file mode 100644 index 11700723769f..000000000000 --- a/internal/terraform/testdata/apply-targeted-module-unrelated-outputs/main.tf +++ /dev/null @@ -1,37 +0,0 @@ -resource "aws_instance" "foo" {} - -module "child1" { - source = "./child1" - instance_id = "${aws_instance.foo.id}" -} - -module "child2" { - source = "./child2" -} - -output "child1_id" { - value = "${module.child1.instance_id}" -} - -output "child1_given_id" { - value = "${module.child1.given_instance_id}" -} - -output "child2_id" { - # This should get updated even though we're targeting specifically - # module.child2, because outputs are implicitly targeted when their - # dependencies are. - value = "${module.child2.instance_id}" -} - -output "all_ids" { - # Here we are intentionally referencing values covering three different scenarios: - # - not targeted and not already in state - # - not targeted and already in state - # - targeted - # This is important because this output must appear in the graph after - # target filtering in case the targeted node changes its value, but we must - # therefore silently ignore the failure that results from trying to - # interpolate the un-targeted, not-in-state node. - value = "${aws_instance.foo.id} ${module.child1.instance_id} ${module.child2.instance_id}" -} diff --git a/internal/terraform/testdata/apply-targeted-module/child/main.tf b/internal/terraform/testdata/apply-targeted-module/child/main.tf deleted file mode 100644 index 7872c90fcf5a..000000000000 --- a/internal/terraform/testdata/apply-targeted-module/child/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "foo" { - num = "2" -} - -resource "aws_instance" "bar" { - num = "2" -} diff --git a/internal/terraform/testdata/apply-targeted-module/main.tf b/internal/terraform/testdata/apply-targeted-module/main.tf deleted file mode 100644 index 938ce3a56069..000000000000 --- a/internal/terraform/testdata/apply-targeted-module/main.tf +++ /dev/null @@ -1,11 +0,0 @@ -module "child" { - source = "./child" -} - -resource "aws_instance" "foo" { - foo = "bar" -} - -resource "aws_instance" "bar" { - foo = "bar" -} diff --git a/internal/terraform/testdata/apply-targeted-resource-orphan-module/child/main.tf b/internal/terraform/testdata/apply-targeted-resource-orphan-module/child/main.tf deleted file mode 100644 index 6ff716a4d4c1..000000000000 --- a/internal/terraform/testdata/apply-targeted-resource-orphan-module/child/main.tf +++ /dev/null @@ -1 +0,0 @@ -resource "aws_instance" "bar" {} diff --git a/internal/terraform/testdata/apply-targeted-resource-orphan-module/main.tf b/internal/terraform/testdata/apply-targeted-resource-orphan-module/main.tf deleted file mode 100644 index 0c15c4bb2e12..000000000000 --- a/internal/terraform/testdata/apply-targeted-resource-orphan-module/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -//module "child" { -// source = "./child" -//} - -resource "aws_instance" "foo" {} diff --git a/internal/terraform/testdata/apply-targeted/main.tf b/internal/terraform/testdata/apply-targeted/main.tf deleted file mode 100644 index b07fc97f4d46..000000000000 --- a/internal/terraform/testdata/apply-targeted/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "foo" { - num = "2" -} - -resource "aws_instance" "bar" { - foo = "bar" -} diff --git a/internal/terraform/testdata/apply-terraform-workspace/main.tf b/internal/terraform/testdata/apply-terraform-workspace/main.tf deleted file mode 100644 index cc50f578fac4..000000000000 --- a/internal/terraform/testdata/apply-terraform-workspace/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -output "output" { - value = "${terraform.workspace}" -} diff --git a/internal/terraform/testdata/apply-unknown-interpolate/child/main.tf b/internal/terraform/testdata/apply-unknown-interpolate/child/main.tf deleted file mode 100644 index 1caedabc4586..000000000000 --- a/internal/terraform/testdata/apply-unknown-interpolate/child/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -variable "value" {} - -resource "aws_instance" "bar" { - foo = "${var.value}" -} diff --git a/internal/terraform/testdata/apply-unknown-interpolate/main.tf b/internal/terraform/testdata/apply-unknown-interpolate/main.tf deleted file mode 100644 index 1ee7dd6cbc4b..000000000000 --- a/internal/terraform/testdata/apply-unknown-interpolate/main.tf +++ /dev/null @@ -1,6 +0,0 @@ -resource "aws_instance" "foo" {} - -module "child" { - source = "./child" - value = "${aws_instance.foo.nope}" -} diff --git a/internal/terraform/testdata/apply-unknown/main.tf b/internal/terraform/testdata/apply-unknown/main.tf deleted file mode 100644 index 98f5ee87e9f0..000000000000 --- a/internal/terraform/testdata/apply-unknown/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_instance" "foo" { - num = "2" -} diff --git a/internal/terraform/testdata/apply-unstable/main.tf b/internal/terraform/testdata/apply-unstable/main.tf deleted file mode 100644 index 32754bb46640..000000000000 --- a/internal/terraform/testdata/apply-unstable/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "test_resource" "foo" { - random = "${uuid()}" -} diff --git a/internal/terraform/testdata/apply-vars-env/main.tf b/internal/terraform/testdata/apply-vars-env/main.tf deleted file mode 100644 index 1b62ad633826..000000000000 --- a/internal/terraform/testdata/apply-vars-env/main.tf +++ /dev/null @@ -1,20 +0,0 @@ -variable "string" { - default = "foo" - type = string -} - -variable "list" { - default = [] - type = list(string) -} - -variable "map" { - default = {} - type = map(string) -} - -resource "aws_instance" "bar" { - string = var.string - list = var.list - map = var.map -} diff --git a/internal/terraform/testdata/apply-vars/main.tf b/internal/terraform/testdata/apply-vars/main.tf deleted file mode 100644 index dc413c0be4cc..000000000000 --- a/internal/terraform/testdata/apply-vars/main.tf +++ /dev/null @@ -1,33 +0,0 @@ -variable "amis" { - default = { - us-east-1 = "foo" - us-west-2 = "foo" - } -} - -variable "test_list" { - type = list(string) -} - -variable "test_map" { - type = map(string) -} - -variable "bar" { - default = "baz" -} - -variable "foo" {} - -resource "aws_instance" "foo" { - num = "2" - bar = var.bar - list = var.test_list - map = var.test_map -} - -resource "aws_instance" "bar" { - foo = var.foo - bar = var.amis[var.foo] - baz = var.amis["us-east-1"] -} diff --git a/internal/terraform/testdata/context-required-version-module/child/main.tf b/internal/terraform/testdata/context-required-version-module/child/main.tf deleted file mode 100644 index 3b52ffab9112..000000000000 --- a/internal/terraform/testdata/context-required-version-module/child/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -terraform { - required_version = ">= 0.5.0" -} diff --git a/internal/terraform/testdata/context-required-version-module/main.tf b/internal/terraform/testdata/context-required-version-module/main.tf deleted file mode 100644 index 0f6991c536ca..000000000000 --- a/internal/terraform/testdata/context-required-version-module/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -module "child" { - source = "./child" -} diff --git a/internal/terraform/testdata/context-required-version/main.tf b/internal/terraform/testdata/context-required-version/main.tf deleted file mode 100644 index 75db792903e4..000000000000 --- a/internal/terraform/testdata/context-required-version/main.tf +++ /dev/null @@ -1 +0,0 @@ -terraform {} diff --git a/internal/terraform/testdata/data-source-read-with-plan-error/main.tf b/internal/terraform/testdata/data-source-read-with-plan-error/main.tf deleted file mode 100644 index 2559406f7ab5..000000000000 --- a/internal/terraform/testdata/data-source-read-with-plan-error/main.tf +++ /dev/null @@ -1,12 +0,0 @@ -resource "aws_instance" "foo" { -} - -// this will be postponed until apply -data "aws_data_source" "foo" { - foo = aws_instance.foo.id -} - -// this will cause an error in the final plan -resource "test_instance" "bar" { - foo = "error" -} diff --git a/internal/terraform/testdata/destroy-module-with-provider/main.tf b/internal/terraform/testdata/destroy-module-with-provider/main.tf deleted file mode 100644 index 3b183ecac498..000000000000 --- a/internal/terraform/testdata/destroy-module-with-provider/main.tf +++ /dev/null @@ -1,11 +0,0 @@ -// this is the provider that should actually be used by orphaned resources -provider "aws" { - alias = "bar" -} - -module "mod" { - source = "./mod" - providers = { - aws.foo = "aws.bar" - } -} diff --git a/internal/terraform/testdata/destroy-module-with-provider/mod/main.tf b/internal/terraform/testdata/destroy-module-with-provider/mod/main.tf deleted file mode 100644 index 3e360ee46048..000000000000 --- a/internal/terraform/testdata/destroy-module-with-provider/mod/main.tf +++ /dev/null @@ -1,6 +0,0 @@ -provider "aws" { - alias = "foo" -} - -// removed module configuration referencing aws.foo, which was passed in by the -// root module diff --git a/internal/terraform/testdata/destroy-targeted/child/main.tf b/internal/terraform/testdata/destroy-targeted/child/main.tf deleted file mode 100644 index 47ef076b12de..000000000000 --- a/internal/terraform/testdata/destroy-targeted/child/main.tf +++ /dev/null @@ -1,10 +0,0 @@ -variable "in" { -} - -resource "aws_instance" "b" { - foo = var.in -} - -output "out" { - value = var.in -} diff --git a/internal/terraform/testdata/destroy-targeted/main.tf b/internal/terraform/testdata/destroy-targeted/main.tf deleted file mode 100644 index 70048b50c017..000000000000 --- a/internal/terraform/testdata/destroy-targeted/main.tf +++ /dev/null @@ -1,12 +0,0 @@ -resource "aws_instance" "a" { - foo = "bar" -} - -module "child" { - source = "./child" - in = aws_instance.a.id -} - -output "out" { - value = aws_instance.a.id -} diff --git a/internal/terraform/testdata/empty/main.tf b/internal/terraform/testdata/empty/main.tf deleted file mode 100644 index 8974d9ed2542..000000000000 --- a/internal/terraform/testdata/empty/main.tf +++ /dev/null @@ -1 +0,0 @@ -# Empty, use this for any test that requires a module but no config. diff --git a/internal/terraform/testdata/eval-context-basic/child/main.tf b/internal/terraform/testdata/eval-context-basic/child/main.tf deleted file mode 100644 index e24069df759f..000000000000 --- a/internal/terraform/testdata/eval-context-basic/child/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -variable "list" { -} - - -output "result" { - value = length(var.list) -} diff --git a/internal/terraform/testdata/eval-context-basic/main.tf b/internal/terraform/testdata/eval-context-basic/main.tf deleted file mode 100644 index 2dc96ad86351..000000000000 --- a/internal/terraform/testdata/eval-context-basic/main.tf +++ /dev/null @@ -1,39 +0,0 @@ -variable "number" { - default = 3 -} - -variable "string" { - default = "Hello, World" -} - -variable "map" { - type = map(string) - default = { - "foo" = "bar", - "baz" = "bat", - } -} - -locals { - result = length(var.list) -} - -variable "list" { - type = list(string) - default = ["red", "orange", "yellow", "green", "blue", "purple"] -} - -resource "test_resource" "example" { - for_each = var.map - name = each.key - tag = each.value -} - -module "child" { - source = "./child" - list = var.list -} - -output "result" { - value = module.child.result -} diff --git a/internal/terraform/testdata/graph-basic/main.tf b/internal/terraform/testdata/graph-basic/main.tf deleted file mode 100644 index a40802cc98eb..000000000000 --- a/internal/terraform/testdata/graph-basic/main.tf +++ /dev/null @@ -1,24 +0,0 @@ -variable "foo" { - default = "bar" - description = "bar" -} - -provider "aws" { - foo = "${openstack_floating_ip.random.value}" -} - -resource "openstack_floating_ip" "random" {} - -resource "aws_security_group" "firewall" {} - -resource "aws_instance" "web" { - ami = "${var.foo}" - security_groups = [ - "foo", - "${aws_security_group.firewall.foo}" - ] -} - -resource "aws_load_balancer" "weblb" { - members = "${aws_instance.web.id_list}" -} diff --git a/internal/terraform/testdata/graph-builder-apply-basic/child/main.tf b/internal/terraform/testdata/graph-builder-apply-basic/child/main.tf deleted file mode 100644 index 79be97bf1618..000000000000 --- a/internal/terraform/testdata/graph-builder-apply-basic/child/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "test_object" "create" { - provisioner "test" {} -} - -resource "test_object" "other" { - test_string = "${test_object.create.test_string}" -} diff --git a/internal/terraform/testdata/graph-builder-apply-basic/main.tf b/internal/terraform/testdata/graph-builder-apply-basic/main.tf deleted file mode 100644 index b42bd439e407..000000000000 --- a/internal/terraform/testdata/graph-builder-apply-basic/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -module "child" { - source = "./child" -} - -resource "test_object" "create" {} - -resource "test_object" "other" { - test_string = "${test_object.create.test_string}" -} diff --git a/internal/terraform/testdata/graph-builder-apply-count/main.tf b/internal/terraform/testdata/graph-builder-apply-count/main.tf deleted file mode 100644 index dee4eb41259a..000000000000 --- a/internal/terraform/testdata/graph-builder-apply-count/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "test_object" "A" { - count = 1 -} - -resource "test_object" "B" { - test_list = test_object.A.*.test_string -} diff --git a/internal/terraform/testdata/graph-builder-apply-dep-cbd/main.tf b/internal/terraform/testdata/graph-builder-apply-dep-cbd/main.tf deleted file mode 100644 index df6f2908cf3a..000000000000 --- a/internal/terraform/testdata/graph-builder-apply-dep-cbd/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -resource "test_object" "A" { - lifecycle { - create_before_destroy = true - } -} - -resource "test_object" "B" { - test_list = test_object.A.*.test_string -} diff --git a/internal/terraform/testdata/graph-builder-apply-double-cbd/main.tf b/internal/terraform/testdata/graph-builder-apply-double-cbd/main.tf deleted file mode 100644 index cb1f73422670..000000000000 --- a/internal/terraform/testdata/graph-builder-apply-double-cbd/main.tf +++ /dev/null @@ -1,13 +0,0 @@ -resource "test_object" "A" { - lifecycle { - create_before_destroy = true - } -} - -resource "test_object" "B" { - test_list = test_object.A.*.test_string - - lifecycle { - create_before_destroy = true - } -} diff --git a/internal/terraform/testdata/graph-builder-apply-module-destroy/A/main.tf b/internal/terraform/testdata/graph-builder-apply-module-destroy/A/main.tf deleted file mode 100644 index 2c427f5c3b2a..000000000000 --- a/internal/terraform/testdata/graph-builder-apply-module-destroy/A/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -variable "input" {} - -resource "test_object" "foo" { - test_string = var.input -} - -output "output" { - value = test_object.foo.id -} diff --git a/internal/terraform/testdata/graph-builder-apply-module-destroy/main.tf b/internal/terraform/testdata/graph-builder-apply-module-destroy/main.tf deleted file mode 100644 index 3c566646d137..000000000000 --- a/internal/terraform/testdata/graph-builder-apply-module-destroy/main.tf +++ /dev/null @@ -1,13 +0,0 @@ -variable "input" { - default = "value" -} - -module "A" { - source = "./A" - input = var.input -} - -module "B" { - source = "./A" - input = module.A.output -} diff --git a/internal/terraform/testdata/graph-builder-apply-orphan-update/main.tf b/internal/terraform/testdata/graph-builder-apply-orphan-update/main.tf deleted file mode 100644 index 22e7ae0f1a19..000000000000 --- a/internal/terraform/testdata/graph-builder-apply-orphan-update/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "test_object" "b" { - test_string = "changed" -} diff --git a/internal/terraform/testdata/graph-builder-apply-provisioner/main.tf b/internal/terraform/testdata/graph-builder-apply-provisioner/main.tf deleted file mode 100644 index 1ea5d2122ee2..000000000000 --- a/internal/terraform/testdata/graph-builder-apply-provisioner/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "test_object" "foo" { - provisioner "test" {} -} diff --git a/internal/terraform/testdata/graph-builder-apply-target-module/child1/main.tf b/internal/terraform/testdata/graph-builder-apply-target-module/child1/main.tf deleted file mode 100644 index 7ac75f5edb9b..000000000000 --- a/internal/terraform/testdata/graph-builder-apply-target-module/child1/main.tf +++ /dev/null @@ -1,11 +0,0 @@ -variable "instance_id" {} - -output "instance_id" { - value = "${var.instance_id}" -} - -resource "test_object" "foo" { - triggers = { - instance_id = "${var.instance_id}" - } -} diff --git a/internal/terraform/testdata/graph-builder-apply-target-module/child2/main.tf b/internal/terraform/testdata/graph-builder-apply-target-module/child2/main.tf deleted file mode 100644 index 0afe7efac644..000000000000 --- a/internal/terraform/testdata/graph-builder-apply-target-module/child2/main.tf +++ /dev/null @@ -1 +0,0 @@ -resource "test_object" "foo" {} diff --git a/internal/terraform/testdata/graph-builder-apply-target-module/main.tf b/internal/terraform/testdata/graph-builder-apply-target-module/main.tf deleted file mode 100644 index 994d8fca17dc..000000000000 --- a/internal/terraform/testdata/graph-builder-apply-target-module/main.tf +++ /dev/null @@ -1,10 +0,0 @@ -resource "test_object" "foo" {} - -module "child1" { - source = "./child1" - instance_id = "${test_object.foo.id}" -} - -module "child2" { - source = "./child2" -} diff --git a/internal/terraform/testdata/graph-builder-orphan-alias/main.tf b/internal/terraform/testdata/graph-builder-orphan-alias/main.tf deleted file mode 100644 index 039881847c51..000000000000 --- a/internal/terraform/testdata/graph-builder-orphan-alias/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -provider "test" { - alias = "foo" -} diff --git a/internal/terraform/testdata/graph-builder-plan-attr-as-blocks/attr-as-blocks.tf b/internal/terraform/testdata/graph-builder-plan-attr-as-blocks/attr-as-blocks.tf deleted file mode 100644 index d154cc264218..000000000000 --- a/internal/terraform/testdata/graph-builder-plan-attr-as-blocks/attr-as-blocks.tf +++ /dev/null @@ -1,8 +0,0 @@ -resource "test_thing" "a" { -} - -resource "test_thing" "b" { - nested { - foo = test_thing.a.id - } -} diff --git a/internal/terraform/testdata/graph-builder-plan-basic/main.tf b/internal/terraform/testdata/graph-builder-plan-basic/main.tf deleted file mode 100644 index df74468a1906..000000000000 --- a/internal/terraform/testdata/graph-builder-plan-basic/main.tf +++ /dev/null @@ -1,33 +0,0 @@ -variable "foo" { - default = "bar" - description = "bar" -} - -provider "aws" { - test_string = "${openstack_floating_ip.random.test_string}" -} - -resource "openstack_floating_ip" "random" {} - -resource "aws_security_group" "firewall" {} - -resource "aws_instance" "web" { - test_string = var.foo - - test_list = [ - "foo", - aws_security_group.firewall.test_string, - ] -} - -resource "aws_load_balancer" "weblb" { - test_list = aws_instance.web.test_list -} - -locals { - instance_id = "${aws_instance.web.test_string}" -} - -output "instance_id" { - value = "${local.instance_id}" -} diff --git a/internal/terraform/testdata/graph-builder-plan-dynblock/dynblock.tf b/internal/terraform/testdata/graph-builder-plan-dynblock/dynblock.tf deleted file mode 100644 index 8946969775c1..000000000000 --- a/internal/terraform/testdata/graph-builder-plan-dynblock/dynblock.tf +++ /dev/null @@ -1,14 +0,0 @@ -resource "test_thing" "a" { -} - -resource "test_thing" "b" { -} - -resource "test_thing" "c" { - dynamic "nested" { - for_each = test_thing.a.list - content { - foo = test_thing.b.id - } - } -} diff --git a/internal/terraform/testdata/graph-builder-plan-target-module-provider/child1/main.tf b/internal/terraform/testdata/graph-builder-plan-target-module-provider/child1/main.tf deleted file mode 100644 index f95800f7a0d9..000000000000 --- a/internal/terraform/testdata/graph-builder-plan-target-module-provider/child1/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -variable "key" {} - -provider "test" { - test_string = "${var.key}" -} - -resource "test_object" "foo" {} diff --git a/internal/terraform/testdata/graph-builder-plan-target-module-provider/child2/main.tf b/internal/terraform/testdata/graph-builder-plan-target-module-provider/child2/main.tf deleted file mode 100644 index f95800f7a0d9..000000000000 --- a/internal/terraform/testdata/graph-builder-plan-target-module-provider/child2/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -variable "key" {} - -provider "test" { - test_string = "${var.key}" -} - -resource "test_object" "foo" {} diff --git a/internal/terraform/testdata/graph-builder-plan-target-module-provider/main.tf b/internal/terraform/testdata/graph-builder-plan-target-module-provider/main.tf deleted file mode 100644 index d5a01db9a0d5..000000000000 --- a/internal/terraform/testdata/graph-builder-plan-target-module-provider/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -module "child1" { - source = "./child1" - key = "!" -} - -module "child2" { - source = "./child2" - key = "!" -} diff --git a/internal/terraform/testdata/import-module/child/main.tf b/internal/terraform/testdata/import-module/child/main.tf deleted file mode 100644 index 8a8164b3b24b..000000000000 --- a/internal/terraform/testdata/import-module/child/main.tf +++ /dev/null @@ -1,10 +0,0 @@ -# Empty -provider "aws" {} - -resource "aws_instance" "foo" { - id = "bar" -} - -module "nested" { - source = "./submodule" -} diff --git a/internal/terraform/testdata/import-module/child/submodule/main.tf b/internal/terraform/testdata/import-module/child/submodule/main.tf deleted file mode 100644 index 93c90158bb13..000000000000 --- a/internal/terraform/testdata/import-module/child/submodule/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_instance" "foo" { - id = "baz" -} diff --git a/internal/terraform/testdata/import-module/main.tf b/internal/terraform/testdata/import-module/main.tf deleted file mode 100644 index c899a2c510e3..000000000000 --- a/internal/terraform/testdata/import-module/main.tf +++ /dev/null @@ -1,11 +0,0 @@ -provider "aws" { - foo = "bar" -} - -module "child" { - count = 1 - source = "./child" - providers = { - aws = aws - } -} diff --git a/internal/terraform/testdata/import-provider-locals/main.tf b/internal/terraform/testdata/import-provider-locals/main.tf deleted file mode 100644 index a83512ccd98e..000000000000 --- a/internal/terraform/testdata/import-provider-locals/main.tf +++ /dev/null @@ -1,13 +0,0 @@ -variable "foo" {} - -locals { - baz = "baz-${var.foo}" -} - -provider "aws" { - foo = "${local.baz}" -} - -resource "aws_instance" "foo" { - id = "bar" -} diff --git a/internal/terraform/testdata/import-provider-resources/main.tf b/internal/terraform/testdata/import-provider-resources/main.tf deleted file mode 100644 index a99ee5e94160..000000000000 --- a/internal/terraform/testdata/import-provider-resources/main.tf +++ /dev/null @@ -1,11 +0,0 @@ -provider "aws" { - value = "${test_instance.bar.id}" -} - -resource "aws_instance" "foo" { - bar = "value" -} - -resource "test_instance" "bar" { - value = "yes" -} diff --git a/internal/terraform/testdata/import-provider-vars/main.tf b/internal/terraform/testdata/import-provider-vars/main.tf deleted file mode 100644 index 6a88bc926b86..000000000000 --- a/internal/terraform/testdata/import-provider-vars/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -variable "foo" {} - -provider "aws" { - foo = "${var.foo}" -} - -resource "aws_instance" "foo" { - id = "bar" -} diff --git a/internal/terraform/testdata/import-provider/main.tf b/internal/terraform/testdata/import-provider/main.tf deleted file mode 100644 index 5d41fb3e6162..000000000000 --- a/internal/terraform/testdata/import-provider/main.tf +++ /dev/null @@ -1,6 +0,0 @@ -provider "aws" { - foo = "bar" -} - -resource "aws_instance" "foo" { -} diff --git a/internal/terraform/testdata/input-interpolate-var/child/main.tf b/internal/terraform/testdata/input-interpolate-var/child/main.tf deleted file mode 100644 index beb8c098c095..000000000000 --- a/internal/terraform/testdata/input-interpolate-var/child/main.tf +++ /dev/null @@ -1,6 +0,0 @@ -variable "length" { } - -resource "template_file" "temp" { - count = var.length - template = "foo" -} diff --git a/internal/terraform/testdata/input-interpolate-var/main.tf b/internal/terraform/testdata/input-interpolate-var/main.tf deleted file mode 100644 index 4e68495e7b9d..000000000000 --- a/internal/terraform/testdata/input-interpolate-var/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -module "source" { - source = "./source" -} -module "child" { - source = "./child" - length = module.source.length -} diff --git a/internal/terraform/testdata/input-interpolate-var/source/main.tf b/internal/terraform/testdata/input-interpolate-var/source/main.tf deleted file mode 100644 index 1405fe296d78..000000000000 --- a/internal/terraform/testdata/input-interpolate-var/source/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -output "length" { - value = 3 -} diff --git a/internal/terraform/testdata/input-module-data-vars/child/main.tf b/internal/terraform/testdata/input-module-data-vars/child/main.tf deleted file mode 100644 index aa5d69bd5f8a..000000000000 --- a/internal/terraform/testdata/input-module-data-vars/child/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -variable "in" {} - -output "out" { - value = "${var.in}" -} diff --git a/internal/terraform/testdata/input-module-data-vars/main.tf b/internal/terraform/testdata/input-module-data-vars/main.tf deleted file mode 100644 index 0a327b10247f..000000000000 --- a/internal/terraform/testdata/input-module-data-vars/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -data "null_data_source" "bar" { - foo = ["a", "b"] -} - -module "child" { - source = "./child" - in = "${data.null_data_source.bar.foo[1]}" -} diff --git a/internal/terraform/testdata/input-provider-multi/main.tf b/internal/terraform/testdata/input-provider-multi/main.tf deleted file mode 100644 index db49fd3b0a79..000000000000 --- a/internal/terraform/testdata/input-provider-multi/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -provider "aws" { - alias = "east" -} - -resource "aws_instance" "foo" { - provider = aws.east -} - -resource "aws_instance" "bar" {} diff --git a/internal/terraform/testdata/input-provider-once/child/main.tf b/internal/terraform/testdata/input-provider-once/child/main.tf deleted file mode 100644 index ca39ff5e561b..000000000000 --- a/internal/terraform/testdata/input-provider-once/child/main.tf +++ /dev/null @@ -1,2 +0,0 @@ -provider "aws" {} -resource "aws_instance" "bar" {} diff --git a/internal/terraform/testdata/input-provider-once/main.tf b/internal/terraform/testdata/input-provider-once/main.tf deleted file mode 100644 index 006a74087c51..000000000000 --- a/internal/terraform/testdata/input-provider-once/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -resource "aws_instance" "foo" {} - -module "child" { - source = "./child" -} diff --git a/internal/terraform/testdata/input-provider-vars/main.tf b/internal/terraform/testdata/input-provider-vars/main.tf deleted file mode 100644 index 692bfb30f3bc..000000000000 --- a/internal/terraform/testdata/input-provider-vars/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -variable "foo" {} - -resource "aws_instance" "foo" { - foo = "${var.foo}" -} diff --git a/internal/terraform/testdata/input-provider-with-vars-and-module/child/main.tf b/internal/terraform/testdata/input-provider-with-vars-and-module/child/main.tf deleted file mode 100644 index 7ec25bda0c90..000000000000 --- a/internal/terraform/testdata/input-provider-with-vars-and-module/child/main.tf +++ /dev/null @@ -1 +0,0 @@ -resource "aws_instance" "foo" { } diff --git a/internal/terraform/testdata/input-provider-with-vars-and-module/main.tf b/internal/terraform/testdata/input-provider-with-vars-and-module/main.tf deleted file mode 100644 index c5112dca05f1..000000000000 --- a/internal/terraform/testdata/input-provider-with-vars-and-module/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -provider "aws" { - access_key = "abc123" -} - -module "child" { - source = "./child" -} diff --git a/internal/terraform/testdata/input-provider-with-vars/main.tf b/internal/terraform/testdata/input-provider-with-vars/main.tf deleted file mode 100644 index d8f9311150e6..000000000000 --- a/internal/terraform/testdata/input-provider-with-vars/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -variable "foo" {} - -provider "aws" { - foo = "${var.foo}" -} - -resource "aws_instance" "foo" {} diff --git a/internal/terraform/testdata/input-provider/main.tf b/internal/terraform/testdata/input-provider/main.tf deleted file mode 100644 index 919f140bba6b..000000000000 --- a/internal/terraform/testdata/input-provider/main.tf +++ /dev/null @@ -1 +0,0 @@ -resource "aws_instance" "foo" {} diff --git a/internal/terraform/testdata/input-submodule-count/main.tf b/internal/terraform/testdata/input-submodule-count/main.tf deleted file mode 100644 index 723a15c6d5eb..000000000000 --- a/internal/terraform/testdata/input-submodule-count/main.tf +++ /dev/null @@ -1,4 +0,0 @@ -module "mod" { - source = "./mod" - instance_count = 2 -} diff --git a/internal/terraform/testdata/input-submodule-count/mod/main.tf b/internal/terraform/testdata/input-submodule-count/mod/main.tf deleted file mode 100644 index dd7cf3d9a84a..000000000000 --- a/internal/terraform/testdata/input-submodule-count/mod/main.tf +++ /dev/null @@ -1,11 +0,0 @@ -variable "instance_count" { -} - -resource "aws_instance" "foo" { - count = "${var.instance_count}" -} - -module "submod" { - source = "./submod" - list = ["${aws_instance.foo.*.id}"] -} diff --git a/internal/terraform/testdata/input-submodule-count/mod/submod/main.tf b/internal/terraform/testdata/input-submodule-count/mod/submod/main.tf deleted file mode 100644 index 732ce43b1ab4..000000000000 --- a/internal/terraform/testdata/input-submodule-count/mod/submod/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -variable "list" { - type = list(string) -} - -resource "aws_instance" "bar" { - count = var.list[0] -} diff --git a/internal/terraform/testdata/input-variables/main.tf b/internal/terraform/testdata/input-variables/main.tf deleted file mode 100644 index 9d6d49aa3988..000000000000 --- a/internal/terraform/testdata/input-variables/main.tf +++ /dev/null @@ -1,30 +0,0 @@ -# Required -variable "foo" { -} - -# Optional -variable "bar" { - default = "baz" -} - -# Mapping -variable "map" { - default = { - foo = "bar" - } -} - -# Complex Object Types -variable "object_map" { - type = map(object({ - foo = string, - bar = any - })) -} - -variable "object_list" { - type = list(object({ - foo = string, - bar = any - })) -} diff --git a/internal/terraform/testdata/issue-5254/step-0/main.tf b/internal/terraform/testdata/issue-5254/step-0/main.tf deleted file mode 100644 index dd666eba18cb..000000000000 --- a/internal/terraform/testdata/issue-5254/step-0/main.tf +++ /dev/null @@ -1,12 +0,0 @@ -variable "c" { - default = 1 -} - -resource "template_file" "parent" { - count = var.c - template = "Hi" -} - -resource "template_file" "child" { - template = "${join(",", template_file.parent.*.template)} ok" -} diff --git a/internal/terraform/testdata/issue-5254/step-1/main.tf b/internal/terraform/testdata/issue-5254/step-1/main.tf deleted file mode 100644 index 3510fe1c4b44..000000000000 --- a/internal/terraform/testdata/issue-5254/step-1/main.tf +++ /dev/null @@ -1,13 +0,0 @@ -variable "c" { - default = 1 -} - -resource "template_file" "parent" { - count = var.c - template = "Hi" -} - -resource "template_file" "child" { - template = join(",", template_file.parent.*.template) - __template_requires_new = true -} diff --git a/internal/terraform/testdata/issue-7824/main.tf b/internal/terraform/testdata/issue-7824/main.tf deleted file mode 100644 index ec76bc39223d..000000000000 --- a/internal/terraform/testdata/issue-7824/main.tf +++ /dev/null @@ -1,6 +0,0 @@ -variable "test" { - type = map(string) - default = { - "test" = "1" - } -} \ No newline at end of file diff --git a/internal/terraform/testdata/issue-9549/main.tf b/internal/terraform/testdata/issue-9549/main.tf deleted file mode 100644 index 5bf28c66d0c8..000000000000 --- a/internal/terraform/testdata/issue-9549/main.tf +++ /dev/null @@ -1,11 +0,0 @@ -module "mod" { - source = "./mod" -} - -output "out" { - value = module.mod.base_config["base_template"] -} - -resource "template_instance" "root_template" { - foo = module.mod.base_config["base_template"] -} diff --git a/internal/terraform/testdata/issue-9549/mod/main.tf b/internal/terraform/testdata/issue-9549/mod/main.tf deleted file mode 100644 index aedf9f003ed7..000000000000 --- a/internal/terraform/testdata/issue-9549/mod/main.tf +++ /dev/null @@ -1,10 +0,0 @@ -resource "template_instance" "example" { - compute_value = "template text" - compute = "value" -} - -output "base_config" { - value = { - base_template = template_instance.example.value - } -} diff --git a/internal/terraform/testdata/nested-resource-count-plan/main.tf b/internal/terraform/testdata/nested-resource-count-plan/main.tf deleted file mode 100644 index f803fd1f6541..000000000000 --- a/internal/terraform/testdata/nested-resource-count-plan/main.tf +++ /dev/null @@ -1,11 +0,0 @@ -resource "aws_instance" "foo" { - count = 2 -} - -resource "aws_instance" "bar" { - count = "${length(aws_instance.foo.*.id)}" -} - -resource "aws_instance" "baz" { - count = "${length(aws_instance.bar.*.id)}" -} diff --git a/internal/terraform/testdata/plan-block-nesting-group/block-nesting-group.tf b/internal/terraform/testdata/plan-block-nesting-group/block-nesting-group.tf deleted file mode 100644 index 9284072dc9c1..000000000000 --- a/internal/terraform/testdata/plan-block-nesting-group/block-nesting-group.tf +++ /dev/null @@ -1,2 +0,0 @@ -resource "test" "foo" { -} diff --git a/internal/terraform/testdata/plan-cbd-depends-datasource/main.tf b/internal/terraform/testdata/plan-cbd-depends-datasource/main.tf deleted file mode 100644 index b523204a8de4..000000000000 --- a/internal/terraform/testdata/plan-cbd-depends-datasource/main.tf +++ /dev/null @@ -1,14 +0,0 @@ -resource "aws_instance" "foo" { - count = 2 - num = "2" - computed = data.aws_vpc.bar[count.index].id - - lifecycle { - create_before_destroy = true - } -} - -data "aws_vpc" "bar" { - count = 2 - foo = count.index -} diff --git a/internal/terraform/testdata/plan-cbd-maintain-root/main.tf b/internal/terraform/testdata/plan-cbd-maintain-root/main.tf deleted file mode 100644 index 99c96b9eee42..000000000000 --- a/internal/terraform/testdata/plan-cbd-maintain-root/main.tf +++ /dev/null @@ -1,19 +0,0 @@ -resource "aws_instance" "foo" { - count = "2" - - lifecycle { - create_before_destroy = true - } -} - -resource "aws_instance" "bar" { - count = "2" - - lifecycle { - create_before_destroy = true - } -} - -output "out" { - value = "${aws_instance.foo.0.id}" -} diff --git a/internal/terraform/testdata/plan-cbd/main.tf b/internal/terraform/testdata/plan-cbd/main.tf deleted file mode 100644 index 83d173a53573..000000000000 --- a/internal/terraform/testdata/plan-cbd/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -resource "aws_instance" "foo" { - lifecycle { - create_before_destroy = true - } -} diff --git a/internal/terraform/testdata/plan-close-module-provider/main.tf b/internal/terraform/testdata/plan-close-module-provider/main.tf deleted file mode 100644 index ba846846994e..000000000000 --- a/internal/terraform/testdata/plan-close-module-provider/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -module "mod" { - source = "./mod" -} diff --git a/internal/terraform/testdata/plan-close-module-provider/mod/main.tf b/internal/terraform/testdata/plan-close-module-provider/mod/main.tf deleted file mode 100644 index 3ce1991f2025..000000000000 --- a/internal/terraform/testdata/plan-close-module-provider/mod/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -provider "aws" { - alias = "mod" -} - -resource "aws_instance" "bar" { - provider = "aws.mod" -} diff --git a/internal/terraform/testdata/plan-computed-attr-ref-type-mismatch/main.tf b/internal/terraform/testdata/plan-computed-attr-ref-type-mismatch/main.tf deleted file mode 100644 index 41761b2d5dbe..000000000000 --- a/internal/terraform/testdata/plan-computed-attr-ref-type-mismatch/main.tf +++ /dev/null @@ -1,10 +0,0 @@ -resource "aws_ami_list" "foo" { - # assume this has a computed attr called "ids" -} - -resource "aws_instance" "foo" { - # this is erroneously referencing the list of all ids. The value of this - # is unknown during plan, but we should still know that the unknown value - # is a list of strings and so catch this during plan. - ami = "${aws_ami_list.foo.ids}" -} diff --git a/internal/terraform/testdata/plan-computed-data-count/main.tf b/internal/terraform/testdata/plan-computed-data-count/main.tf deleted file mode 100644 index 2d014045271e..000000000000 --- a/internal/terraform/testdata/plan-computed-data-count/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -resource "aws_instance" "foo" { - num = "2" - compute = "foo" -} - -data "aws_vpc" "bar" { - count = 3 - foo = "${aws_instance.foo.foo}" -} diff --git a/internal/terraform/testdata/plan-computed-data-resource/main.tf b/internal/terraform/testdata/plan-computed-data-resource/main.tf deleted file mode 100644 index aff26ebde5e4..000000000000 --- a/internal/terraform/testdata/plan-computed-data-resource/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -resource "aws_instance" "foo" { - num = "2" - compute = "foo" -} - -data "aws_vpc" "bar" { - foo = "${aws_instance.foo.foo}" -} diff --git a/internal/terraform/testdata/plan-computed-in-function/main.tf b/internal/terraform/testdata/plan-computed-in-function/main.tf deleted file mode 100644 index 554394de6aae..000000000000 --- a/internal/terraform/testdata/plan-computed-in-function/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -data "aws_data_source" "foo" { - -} - -resource "aws_instance" "bar" { - attr = "${length(data.aws_data_source.foo.computed)}" -} diff --git a/internal/terraform/testdata/plan-computed-list/main.tf b/internal/terraform/testdata/plan-computed-list/main.tf deleted file mode 100644 index aeec6ba9350c..000000000000 --- a/internal/terraform/testdata/plan-computed-list/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -resource "aws_instance" "foo" { - num = "2" - compute = "list.#" -} - -resource "aws_instance" "bar" { - foo = aws_instance.foo.list.0 -} diff --git a/internal/terraform/testdata/plan-computed-multi-index/main.tf b/internal/terraform/testdata/plan-computed-multi-index/main.tf deleted file mode 100644 index 2d8a799d0587..000000000000 --- a/internal/terraform/testdata/plan-computed-multi-index/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -resource "aws_instance" "foo" { - count = 2 - compute = "ip.#" -} - -resource "aws_instance" "bar" { - count = 1 - foo = "${aws_instance.foo.*.ip[count.index]}" -} diff --git a/internal/terraform/testdata/plan-computed-value-in-map/main.tf b/internal/terraform/testdata/plan-computed-value-in-map/main.tf deleted file mode 100644 index ef2cf08099ab..000000000000 --- a/internal/terraform/testdata/plan-computed-value-in-map/main.tf +++ /dev/null @@ -1,16 +0,0 @@ -resource "aws_computed_source" "intermediates" {} - -module "test_mod" { - source = "./mod" - - services = [ - { - "exists" = "true" - "elb" = "${aws_computed_source.intermediates.computed_read_only}" - }, - { - "otherexists" = " true" - "elb" = "${aws_computed_source.intermediates.computed_read_only}" - }, - ] -} diff --git a/internal/terraform/testdata/plan-computed-value-in-map/mod/main.tf b/internal/terraform/testdata/plan-computed-value-in-map/mod/main.tf deleted file mode 100644 index f6adccf40dab..000000000000 --- a/internal/terraform/testdata/plan-computed-value-in-map/mod/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -variable "services" { - type = list(map(string)) -} - -resource "aws_instance" "inner2" { - looked_up = var.services[0]["elb"] -} - diff --git a/internal/terraform/testdata/plan-computed/main.tf b/internal/terraform/testdata/plan-computed/main.tf deleted file mode 100644 index 71809138b126..000000000000 --- a/internal/terraform/testdata/plan-computed/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -resource "aws_instance" "foo" { - num = "2" - compute = "foo" -} - -resource "aws_instance" "bar" { - foo = "${aws_instance.foo.foo}" -} diff --git a/internal/terraform/testdata/plan-count-computed-module/child/main.tf b/internal/terraform/testdata/plan-count-computed-module/child/main.tf deleted file mode 100644 index f80d699d9c30..000000000000 --- a/internal/terraform/testdata/plan-count-computed-module/child/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -variable "value" {} - -resource "aws_instance" "bar" { - count = "${var.value}" -} diff --git a/internal/terraform/testdata/plan-count-computed-module/main.tf b/internal/terraform/testdata/plan-count-computed-module/main.tf deleted file mode 100644 index c87beb5f896c..000000000000 --- a/internal/terraform/testdata/plan-count-computed-module/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -resource "aws_instance" "foo" { - compute = "foo" -} - -module "child" { - source = "./child" - value = "${aws_instance.foo.foo}" -} diff --git a/internal/terraform/testdata/plan-count-computed/main.tf b/internal/terraform/testdata/plan-count-computed/main.tf deleted file mode 100644 index 8a029236b1e9..000000000000 --- a/internal/terraform/testdata/plan-count-computed/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -resource "aws_instance" "foo" { - num = "2" - compute = "foo" -} - -resource "aws_instance" "bar" { - count = "${aws_instance.foo.foo}" -} diff --git a/internal/terraform/testdata/plan-count-dec/main.tf b/internal/terraform/testdata/plan-count-dec/main.tf deleted file mode 100644 index 7837f58655f7..000000000000 --- a/internal/terraform/testdata/plan-count-dec/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "foo" { - foo = "foo" -} - -resource "aws_instance" "bar" { - foo = "bar" -} diff --git a/internal/terraform/testdata/plan-count-inc/main.tf b/internal/terraform/testdata/plan-count-inc/main.tf deleted file mode 100644 index 3c7fdb9fff79..000000000000 --- a/internal/terraform/testdata/plan-count-inc/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -resource "aws_instance" "foo" { - foo = "foo" - count = 3 -} - -resource "aws_instance" "bar" { - foo = "bar" -} diff --git a/internal/terraform/testdata/plan-count-index/main.tf b/internal/terraform/testdata/plan-count-index/main.tf deleted file mode 100644 index 9a0d1ebbcc2f..000000000000 --- a/internal/terraform/testdata/plan-count-index/main.tf +++ /dev/null @@ -1,4 +0,0 @@ -resource "aws_instance" "foo" { - count = 2 - foo = "${count.index}" -} diff --git a/internal/terraform/testdata/plan-count-module-static-grandchild/child/child/main.tf b/internal/terraform/testdata/plan-count-module-static-grandchild/child/child/main.tf deleted file mode 100644 index 5b75831fdc1e..000000000000 --- a/internal/terraform/testdata/plan-count-module-static-grandchild/child/child/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -variable "value" {} - -resource "aws_instance" "foo" { - count = "${var.value}" -} diff --git a/internal/terraform/testdata/plan-count-module-static-grandchild/child/main.tf b/internal/terraform/testdata/plan-count-module-static-grandchild/child/main.tf deleted file mode 100644 index 4dff927d51e9..000000000000 --- a/internal/terraform/testdata/plan-count-module-static-grandchild/child/main.tf +++ /dev/null @@ -1,6 +0,0 @@ -variable "value" {} - -module "child" { - source = "./child" - value = "${var.value}" -} diff --git a/internal/terraform/testdata/plan-count-module-static-grandchild/main.tf b/internal/terraform/testdata/plan-count-module-static-grandchild/main.tf deleted file mode 100644 index b2c7ca66e7ae..000000000000 --- a/internal/terraform/testdata/plan-count-module-static-grandchild/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -variable "foo" { - default = "3" -} - -module "child" { - source = "./child" - value = "${var.foo}" -} diff --git a/internal/terraform/testdata/plan-count-module-static/child/main.tf b/internal/terraform/testdata/plan-count-module-static/child/main.tf deleted file mode 100644 index 5b75831fdc1e..000000000000 --- a/internal/terraform/testdata/plan-count-module-static/child/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -variable "value" {} - -resource "aws_instance" "foo" { - count = "${var.value}" -} diff --git a/internal/terraform/testdata/plan-count-module-static/main.tf b/internal/terraform/testdata/plan-count-module-static/main.tf deleted file mode 100644 index b2c7ca66e7ae..000000000000 --- a/internal/terraform/testdata/plan-count-module-static/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -variable "foo" { - default = "3" -} - -module "child" { - source = "./child" - value = "${var.foo}" -} diff --git a/internal/terraform/testdata/plan-count-one-index/main.tf b/internal/terraform/testdata/plan-count-one-index/main.tf deleted file mode 100644 index 58d4acf7113f..000000000000 --- a/internal/terraform/testdata/plan-count-one-index/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -resource "aws_instance" "foo" { - count = 1 - foo = "foo" -} - -resource "aws_instance" "bar" { - foo = "${aws_instance.foo.0.foo}" -} diff --git a/internal/terraform/testdata/plan-count-splat-reference/main.tf b/internal/terraform/testdata/plan-count-splat-reference/main.tf deleted file mode 100644 index 76834e2555c8..000000000000 --- a/internal/terraform/testdata/plan-count-splat-reference/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -resource "aws_instance" "foo" { - name = "foo ${count.index}" - count = 3 -} - -resource "aws_instance" "bar" { - foo_name = "${aws_instance.foo.*.name[count.index]}" - count = 3 -} diff --git a/internal/terraform/testdata/plan-count-var/main.tf b/internal/terraform/testdata/plan-count-var/main.tf deleted file mode 100644 index 8b8a04333e32..000000000000 --- a/internal/terraform/testdata/plan-count-var/main.tf +++ /dev/null @@ -1,10 +0,0 @@ -variable "instance_count" {} - -resource "aws_instance" "foo" { - count = var.instance_count - foo = "foo" -} - -resource "aws_instance" "bar" { - foo = join(",", aws_instance.foo.*.foo) -} diff --git a/internal/terraform/testdata/plan-count-zero/main.tf b/internal/terraform/testdata/plan-count-zero/main.tf deleted file mode 100644 index 4845cbb0bf22..000000000000 --- a/internal/terraform/testdata/plan-count-zero/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -resource "aws_instance" "foo" { - count = 0 - foo = "foo" -} - -resource "aws_instance" "bar" { - foo = "${aws_instance.foo.*.foo}" -} diff --git a/internal/terraform/testdata/plan-count/main.tf b/internal/terraform/testdata/plan-count/main.tf deleted file mode 100644 index 276670ce4474..000000000000 --- a/internal/terraform/testdata/plan-count/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -resource "aws_instance" "foo" { - count = 5 - foo = "foo" -} - -resource "aws_instance" "bar" { - foo = "${join(",", aws_instance.foo.*.foo)}" -} diff --git a/internal/terraform/testdata/plan-data-depends-on/main.tf b/internal/terraform/testdata/plan-data-depends-on/main.tf deleted file mode 100644 index c7332ad291e8..000000000000 --- a/internal/terraform/testdata/plan-data-depends-on/main.tf +++ /dev/null @@ -1,14 +0,0 @@ -resource "test_resource" "a" { -} - -data "test_data" "d" { - count = 1 - depends_on = [ - test_resource.a - ] -} - -resource "test_resource" "b" { - count = 1 - foo = data.test_data.d[count.index].compute -} diff --git a/internal/terraform/testdata/plan-data-resource-becomes-computed/main.tf b/internal/terraform/testdata/plan-data-resource-becomes-computed/main.tf deleted file mode 100644 index 3f07be3522b9..000000000000 --- a/internal/terraform/testdata/plan-data-resource-becomes-computed/main.tf +++ /dev/null @@ -1,6 +0,0 @@ -resource "aws_instance" "foo" { -} - -data "aws_data_source" "foo" { - foo = "${aws_instance.foo.computed}" -} diff --git a/internal/terraform/testdata/plan-destroy-interpolated-count/main.tf b/internal/terraform/testdata/plan-destroy-interpolated-count/main.tf deleted file mode 100644 index ac0dadbf81f8..000000000000 --- a/internal/terraform/testdata/plan-destroy-interpolated-count/main.tf +++ /dev/null @@ -1,20 +0,0 @@ -variable "list" { - default = ["1", "2"] -} - -resource "aws_instance" "a" { - count = length(var.list) -} - -locals { - ids = aws_instance.a[*].id -} - -module "empty" { - source = "./mod" - input = zipmap(var.list, local.ids) -} - -output "out" { - value = aws_instance.a[*].id -} diff --git a/internal/terraform/testdata/plan-destroy-interpolated-count/mod/main.tf b/internal/terraform/testdata/plan-destroy-interpolated-count/mod/main.tf deleted file mode 100644 index 682e0f0db76a..000000000000 --- a/internal/terraform/testdata/plan-destroy-interpolated-count/mod/main.tf +++ /dev/null @@ -1,2 +0,0 @@ -variable "input" { -} diff --git a/internal/terraform/testdata/plan-destroy/main.tf b/internal/terraform/testdata/plan-destroy/main.tf deleted file mode 100644 index 1b6cdae67b0e..000000000000 --- a/internal/terraform/testdata/plan-destroy/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "foo" { - num = "2" -} - -resource "aws_instance" "bar" { - foo = "${aws_instance.foo.num}" -} diff --git a/internal/terraform/testdata/plan-diffvar/main.tf b/internal/terraform/testdata/plan-diffvar/main.tf deleted file mode 100644 index eccc16ff2c39..000000000000 --- a/internal/terraform/testdata/plan-diffvar/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "foo" { - num = "3" -} - -resource "aws_instance" "bar" { - num = aws_instance.foo.num -} diff --git a/internal/terraform/testdata/plan-empty/main.tf b/internal/terraform/testdata/plan-empty/main.tf deleted file mode 100644 index 88002d078a1b..000000000000 --- a/internal/terraform/testdata/plan-empty/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -resource "aws_instance" "foo" { -} - -resource "aws_instance" "bar" { -} diff --git a/internal/terraform/testdata/plan-escaped-var/main.tf b/internal/terraform/testdata/plan-escaped-var/main.tf deleted file mode 100644 index 5a017207ccf7..000000000000 --- a/internal/terraform/testdata/plan-escaped-var/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_instance" "foo" { - foo = "bar-$${baz}" -} diff --git a/internal/terraform/testdata/plan-for-each-unknown-value/main.tf b/internal/terraform/testdata/plan-for-each-unknown-value/main.tf deleted file mode 100644 index 933ed5f4c322..000000000000 --- a/internal/terraform/testdata/plan-for-each-unknown-value/main.tf +++ /dev/null @@ -1,20 +0,0 @@ -# expressions with variable reference -variable "foo" { - type = string -} - -resource "aws_instance" "foo" { - for_each = toset( - [for i in range(0,3) : sha1("${i}${var.foo}")] - ) - foo = "foo" -} - -# referencing another resource, which means it has some unknown values in it -resource "aws_instance" "one" { - for_each = toset(["a", "b"]) -} - -resource "aws_instance" "two" { - for_each = aws_instance.one -} diff --git a/internal/terraform/testdata/plan-for-each/main.tf b/internal/terraform/testdata/plan-for-each/main.tf deleted file mode 100644 index 94572e20a47f..000000000000 --- a/internal/terraform/testdata/plan-for-each/main.tf +++ /dev/null @@ -1,35 +0,0 @@ -# maps -resource "aws_instance" "foo" { - for_each = { - a = "thing" - b = "another thing" - c = "yet another thing" - } - num = "3" -} - -# sets -resource "aws_instance" "bar" { - for_each = toset([]) -} -resource "aws_instance" "bar2" { - for_each = toset(["z", "y", "x"]) -} - -# an empty map should generate no resource -resource "aws_instance" "baz" { - for_each = {} -} - -# references -resource "aws_instance" "boo" { - foo = aws_instance.foo["a"].num -} - -resource "aws_instance" "bat" { - for_each = { - my_key = aws_instance.boo.foo - } - foo = each.value -} - diff --git a/internal/terraform/testdata/plan-good/main.tf b/internal/terraform/testdata/plan-good/main.tf deleted file mode 100644 index 1b6cdae67b0e..000000000000 --- a/internal/terraform/testdata/plan-good/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "foo" { - num = "2" -} - -resource "aws_instance" "bar" { - foo = "${aws_instance.foo.num}" -} diff --git a/internal/terraform/testdata/plan-ignore-changes-in-map/ignore-changes-in-map.tf b/internal/terraform/testdata/plan-ignore-changes-in-map/ignore-changes-in-map.tf deleted file mode 100644 index 75adcac5c3d7..000000000000 --- a/internal/terraform/testdata/plan-ignore-changes-in-map/ignore-changes-in-map.tf +++ /dev/null @@ -1,13 +0,0 @@ - -resource "test_ignore_changes_map" "foo" { - tags = { - ignored = "from config" - other = "from config" - } - - lifecycle { - ignore_changes = [ - tags["ignored"], - ] - } -} diff --git a/internal/terraform/testdata/plan-ignore-changes-sensitive/ignore-changes-sensitive.tf b/internal/terraform/testdata/plan-ignore-changes-sensitive/ignore-changes-sensitive.tf deleted file mode 100644 index 1f6cc98acede..000000000000 --- a/internal/terraform/testdata/plan-ignore-changes-sensitive/ignore-changes-sensitive.tf +++ /dev/null @@ -1,11 +0,0 @@ -variable "foo" { - sensitive = true -} - -resource "aws_instance" "foo" { - ami = var.foo - - lifecycle { - ignore_changes = [ami] - } -} diff --git a/internal/terraform/testdata/plan-ignore-changes-wildcard/main.tf b/internal/terraform/testdata/plan-ignore-changes-wildcard/main.tf deleted file mode 100644 index ac594a9eb845..000000000000 --- a/internal/terraform/testdata/plan-ignore-changes-wildcard/main.tf +++ /dev/null @@ -1,13 +0,0 @@ -variable "foo" {} - -variable "bar" {} - -resource "aws_instance" "foo" { - ami = "${var.foo}" - instance = "${var.bar}" - foo = "bar" - - lifecycle { - ignore_changes = all - } -} diff --git a/internal/terraform/testdata/plan-ignore-changes-with-flatmaps/main.tf b/internal/terraform/testdata/plan-ignore-changes-with-flatmaps/main.tf deleted file mode 100644 index f61a3d42fc49..000000000000 --- a/internal/terraform/testdata/plan-ignore-changes-with-flatmaps/main.tf +++ /dev/null @@ -1,15 +0,0 @@ -resource "aws_instance" "foo" { - user_data = "x" - require_new = "yes" - - set = [{ - a = "1" - b = "2" - }] - - lst = ["j", "k"] - - lifecycle { - ignore_changes = ["require_new"] - } -} diff --git a/internal/terraform/testdata/plan-ignore-changes/main.tf b/internal/terraform/testdata/plan-ignore-changes/main.tf deleted file mode 100644 index ed17c634497d..000000000000 --- a/internal/terraform/testdata/plan-ignore-changes/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -variable "foo" {} - -resource "aws_instance" "foo" { - ami = var.foo - - lifecycle { - ignore_changes = [ami] - } -} diff --git a/internal/terraform/testdata/plan-list-order/main.tf b/internal/terraform/testdata/plan-list-order/main.tf deleted file mode 100644 index 77db3d0597ea..000000000000 --- a/internal/terraform/testdata/plan-list-order/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "a" { - foo = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 20] -} - -resource "aws_instance" "b" { - foo = "${aws_instance.a.foo}" -} diff --git a/internal/terraform/testdata/plan-local-value-count/main.tf b/internal/terraform/testdata/plan-local-value-count/main.tf deleted file mode 100644 index 34aad96ad650..000000000000 --- a/internal/terraform/testdata/plan-local-value-count/main.tf +++ /dev/null @@ -1,8 +0,0 @@ - -locals { - count = 3 -} - -resource "test_resource" "foo" { - count = "${local.count}" -} diff --git a/internal/terraform/testdata/plan-module-cycle/child/main.tf b/internal/terraform/testdata/plan-module-cycle/child/main.tf deleted file mode 100644 index e2e60c1f086d..000000000000 --- a/internal/terraform/testdata/plan-module-cycle/child/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -variable "in" {} - -output "out" { - value = "${var.in}" -} diff --git a/internal/terraform/testdata/plan-module-cycle/main.tf b/internal/terraform/testdata/plan-module-cycle/main.tf deleted file mode 100644 index e9c459721f53..000000000000 --- a/internal/terraform/testdata/plan-module-cycle/main.tf +++ /dev/null @@ -1,12 +0,0 @@ -module "a" { - source = "./child" - in = "${aws_instance.b.id}" -} - -resource "aws_instance" "b" {} - -resource "aws_instance" "c" { - some_input = "${module.a.out}" - - depends_on = ["aws_instance.b"] -} diff --git a/internal/terraform/testdata/plan-module-deadlock/child/main.tf b/internal/terraform/testdata/plan-module-deadlock/child/main.tf deleted file mode 100644 index 2451bf0542ff..000000000000 --- a/internal/terraform/testdata/plan-module-deadlock/child/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "foo" { - count = "${length("abc")}" - - lifecycle { - create_before_destroy = true - } -} diff --git a/internal/terraform/testdata/plan-module-deadlock/main.tf b/internal/terraform/testdata/plan-module-deadlock/main.tf deleted file mode 100644 index 1f95749fa7ea..000000000000 --- a/internal/terraform/testdata/plan-module-deadlock/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -module "child" { - source = "./child" -} diff --git a/internal/terraform/testdata/plan-module-destroy-gh-1835/a/main.tf b/internal/terraform/testdata/plan-module-destroy-gh-1835/a/main.tf deleted file mode 100644 index ca44c757d015..000000000000 --- a/internal/terraform/testdata/plan-module-destroy-gh-1835/a/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -resource "aws_instance" "a" {} - -output "a_output" { - value = "${aws_instance.a.id}" -} diff --git a/internal/terraform/testdata/plan-module-destroy-gh-1835/b/main.tf b/internal/terraform/testdata/plan-module-destroy-gh-1835/b/main.tf deleted file mode 100644 index 3b0cc6664500..000000000000 --- a/internal/terraform/testdata/plan-module-destroy-gh-1835/b/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -variable "a_id" {} - -resource "aws_instance" "b" { - foo = "echo ${var.a_id}" -} diff --git a/internal/terraform/testdata/plan-module-destroy-gh-1835/main.tf b/internal/terraform/testdata/plan-module-destroy-gh-1835/main.tf deleted file mode 100644 index c2f72c45e329..000000000000 --- a/internal/terraform/testdata/plan-module-destroy-gh-1835/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -module "a_module" { - source = "./a" -} - -module "b_module" { - source = "./b" - a_id = "${module.a_module.a_output}" -} diff --git a/internal/terraform/testdata/plan-module-destroy-multivar/child/main.tf b/internal/terraform/testdata/plan-module-destroy-multivar/child/main.tf deleted file mode 100644 index 6a496f06f6a3..000000000000 --- a/internal/terraform/testdata/plan-module-destroy-multivar/child/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -variable "instance_count" { - default = "1" -} - -resource "aws_instance" "foo" { - count = "${var.instance_count}" - bar = "bar" -} diff --git a/internal/terraform/testdata/plan-module-destroy-multivar/main.tf b/internal/terraform/testdata/plan-module-destroy-multivar/main.tf deleted file mode 100644 index 2f965b68cc11..000000000000 --- a/internal/terraform/testdata/plan-module-destroy-multivar/main.tf +++ /dev/null @@ -1,4 +0,0 @@ -module "child" { - source = "./child" - instance_count = "2" -} diff --git a/internal/terraform/testdata/plan-module-destroy/child/main.tf b/internal/terraform/testdata/plan-module-destroy/child/main.tf deleted file mode 100644 index 98f5ee87e9f0..000000000000 --- a/internal/terraform/testdata/plan-module-destroy/child/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_instance" "foo" { - num = "2" -} diff --git a/internal/terraform/testdata/plan-module-destroy/main.tf b/internal/terraform/testdata/plan-module-destroy/main.tf deleted file mode 100644 index 428f89834db8..000000000000 --- a/internal/terraform/testdata/plan-module-destroy/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -module "child" { - source = "./child" -} - -resource "aws_instance" "foo" { - num = "2" -} diff --git a/internal/terraform/testdata/plan-module-input-computed/child/main.tf b/internal/terraform/testdata/plan-module-input-computed/child/main.tf deleted file mode 100644 index c1a00c5a326d..000000000000 --- a/internal/terraform/testdata/plan-module-input-computed/child/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -variable "input" {} - -resource "aws_instance" "foo" { - foo = "${var.input}" -} diff --git a/internal/terraform/testdata/plan-module-input-computed/main.tf b/internal/terraform/testdata/plan-module-input-computed/main.tf deleted file mode 100644 index 3a0576434fbf..000000000000 --- a/internal/terraform/testdata/plan-module-input-computed/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -module "child" { - input = "${aws_instance.bar.foo}" - source = "./child" -} - -resource "aws_instance" "bar" { - compute = "foo" -} diff --git a/internal/terraform/testdata/plan-module-input-var/child/main.tf b/internal/terraform/testdata/plan-module-input-var/child/main.tf deleted file mode 100644 index c1a00c5a326d..000000000000 --- a/internal/terraform/testdata/plan-module-input-var/child/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -variable "input" {} - -resource "aws_instance" "foo" { - foo = "${var.input}" -} diff --git a/internal/terraform/testdata/plan-module-input-var/main.tf b/internal/terraform/testdata/plan-module-input-var/main.tf deleted file mode 100644 index 3fba315ee2f9..000000000000 --- a/internal/terraform/testdata/plan-module-input-var/main.tf +++ /dev/null @@ -1,10 +0,0 @@ -variable "foo" {} - -module "child" { - input = "${var.foo}" - source = "./child" -} - -resource "aws_instance" "bar" { - foo = "2" -} diff --git a/internal/terraform/testdata/plan-module-input/child/main.tf b/internal/terraform/testdata/plan-module-input/child/main.tf deleted file mode 100644 index c1a00c5a326d..000000000000 --- a/internal/terraform/testdata/plan-module-input/child/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -variable "input" {} - -resource "aws_instance" "foo" { - foo = "${var.input}" -} diff --git a/internal/terraform/testdata/plan-module-input/main.tf b/internal/terraform/testdata/plan-module-input/main.tf deleted file mode 100644 index 2ad8ec0ca105..000000000000 --- a/internal/terraform/testdata/plan-module-input/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -module "child" { - input = "42" - source = "./child" -} - -resource "aws_instance" "bar" { - foo = "2" -} diff --git a/internal/terraform/testdata/plan-module-map-literal/child/main.tf b/internal/terraform/testdata/plan-module-map-literal/child/main.tf deleted file mode 100644 index 912431922a7b..000000000000 --- a/internal/terraform/testdata/plan-module-map-literal/child/main.tf +++ /dev/null @@ -1,12 +0,0 @@ -variable "amap" { - type = map(string) -} - -variable "othermap" { - type = map(string) -} - -resource "aws_instance" "foo" { - tags = "${var.amap}" - meta = "${var.othermap}" -} diff --git a/internal/terraform/testdata/plan-module-map-literal/main.tf b/internal/terraform/testdata/plan-module-map-literal/main.tf deleted file mode 100644 index 90235ed7a2fb..000000000000 --- a/internal/terraform/testdata/plan-module-map-literal/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -module "child" { - source = "./child" - - amap = { - foo = "bar" - } - - othermap = {} -} diff --git a/internal/terraform/testdata/plan-module-multi-var/child/main.tf b/internal/terraform/testdata/plan-module-multi-var/child/main.tf deleted file mode 100644 index ad8dd6073e5f..000000000000 --- a/internal/terraform/testdata/plan-module-multi-var/child/main.tf +++ /dev/null @@ -1,10 +0,0 @@ -variable "things" {} - -resource "aws_instance" "bar" { - baz = "baz" - count = 2 -} - -resource "aws_instance" "foo" { - foo = "${join(",",aws_instance.bar.*.baz)}" -} diff --git a/internal/terraform/testdata/plan-module-multi-var/main.tf b/internal/terraform/testdata/plan-module-multi-var/main.tf deleted file mode 100644 index 40c7618fe09b..000000000000 --- a/internal/terraform/testdata/plan-module-multi-var/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -resource "aws_instance" "parent" { - count = 2 -} - -module "child" { - source = "./child" - things = "${join(",", aws_instance.parent.*.id)}" -} - diff --git a/internal/terraform/testdata/plan-module-provider-defaults-var/child/main.tf b/internal/terraform/testdata/plan-module-provider-defaults-var/child/main.tf deleted file mode 100644 index 5ce4f55fe841..000000000000 --- a/internal/terraform/testdata/plan-module-provider-defaults-var/child/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -provider "aws" { - from = "child" - to = "child" -} - -resource "aws_instance" "foo" { - from = "child" -} diff --git a/internal/terraform/testdata/plan-module-provider-defaults-var/main.tf b/internal/terraform/testdata/plan-module-provider-defaults-var/main.tf deleted file mode 100644 index d3c34908bd1d..000000000000 --- a/internal/terraform/testdata/plan-module-provider-defaults-var/main.tf +++ /dev/null @@ -1,11 +0,0 @@ -module "child" { - source = "./child" -} - -provider "aws" { - from = "${var.foo}" -} - -resource "aws_instance" "foo" {} - -variable "foo" {} diff --git a/internal/terraform/testdata/plan-module-provider-defaults/child/main.tf b/internal/terraform/testdata/plan-module-provider-defaults/child/main.tf deleted file mode 100644 index 5ce4f55fe841..000000000000 --- a/internal/terraform/testdata/plan-module-provider-defaults/child/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -provider "aws" { - from = "child" - to = "child" -} - -resource "aws_instance" "foo" { - from = "child" -} diff --git a/internal/terraform/testdata/plan-module-provider-defaults/main.tf b/internal/terraform/testdata/plan-module-provider-defaults/main.tf deleted file mode 100644 index 5b08577c6e45..000000000000 --- a/internal/terraform/testdata/plan-module-provider-defaults/main.tf +++ /dev/null @@ -1,11 +0,0 @@ -module "child" { - source = "./child" -} - -provider "aws" { - from = "root" -} - -resource "aws_instance" "foo" { - from = "root" -} diff --git a/internal/terraform/testdata/plan-module-provider-inherit-deep/A/main.tf b/internal/terraform/testdata/plan-module-provider-inherit-deep/A/main.tf deleted file mode 100644 index efe683c318e6..000000000000 --- a/internal/terraform/testdata/plan-module-provider-inherit-deep/A/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -module "B" { - source = "../B" -} diff --git a/internal/terraform/testdata/plan-module-provider-inherit-deep/B/main.tf b/internal/terraform/testdata/plan-module-provider-inherit-deep/B/main.tf deleted file mode 100644 index 29cba7fc3b05..000000000000 --- a/internal/terraform/testdata/plan-module-provider-inherit-deep/B/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -module "C" { - source = "../C" -} diff --git a/internal/terraform/testdata/plan-module-provider-inherit-deep/C/main.tf b/internal/terraform/testdata/plan-module-provider-inherit-deep/C/main.tf deleted file mode 100644 index 919f140bba6b..000000000000 --- a/internal/terraform/testdata/plan-module-provider-inherit-deep/C/main.tf +++ /dev/null @@ -1 +0,0 @@ -resource "aws_instance" "foo" {} diff --git a/internal/terraform/testdata/plan-module-provider-inherit-deep/main.tf b/internal/terraform/testdata/plan-module-provider-inherit-deep/main.tf deleted file mode 100644 index 12677b69b228..000000000000 --- a/internal/terraform/testdata/plan-module-provider-inherit-deep/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -module "A" { - source = "./A" -} - -provider "aws" { - from = "root" -} diff --git a/internal/terraform/testdata/plan-module-provider-inherit/child/main.tf b/internal/terraform/testdata/plan-module-provider-inherit/child/main.tf deleted file mode 100644 index 2e890bbc09c6..000000000000 --- a/internal/terraform/testdata/plan-module-provider-inherit/child/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_instance" "foo" { - from = "child" -} diff --git a/internal/terraform/testdata/plan-module-provider-inherit/main.tf b/internal/terraform/testdata/plan-module-provider-inherit/main.tf deleted file mode 100644 index 5b08577c6e45..000000000000 --- a/internal/terraform/testdata/plan-module-provider-inherit/main.tf +++ /dev/null @@ -1,11 +0,0 @@ -module "child" { - source = "./child" -} - -provider "aws" { - from = "root" -} - -resource "aws_instance" "foo" { - from = "root" -} diff --git a/internal/terraform/testdata/plan-module-provider-var/child/main.tf b/internal/terraform/testdata/plan-module-provider-var/child/main.tf deleted file mode 100644 index 599cb99db5b1..000000000000 --- a/internal/terraform/testdata/plan-module-provider-var/child/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -variable "foo" {} - -provider "aws" { - value = "${var.foo}" -} - -resource "aws_instance" "test" { - value = "hello" -} diff --git a/internal/terraform/testdata/plan-module-provider-var/main.tf b/internal/terraform/testdata/plan-module-provider-var/main.tf deleted file mode 100644 index 43675f913c4c..000000000000 --- a/internal/terraform/testdata/plan-module-provider-var/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -variable "foo" { - default = "bar" -} - -module "child" { - source = "./child" - foo = "${var.foo}" -} diff --git a/internal/terraform/testdata/plan-module-var-computed/child/main.tf b/internal/terraform/testdata/plan-module-var-computed/child/main.tf deleted file mode 100644 index 20a301330bc9..000000000000 --- a/internal/terraform/testdata/plan-module-var-computed/child/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "foo" { - compute = "foo" -} - -output "num" { - value = "${aws_instance.foo.foo}" -} diff --git a/internal/terraform/testdata/plan-module-var-computed/main.tf b/internal/terraform/testdata/plan-module-var-computed/main.tf deleted file mode 100644 index b38f538a237d..000000000000 --- a/internal/terraform/testdata/plan-module-var-computed/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -module "child" { - source = "./child" -} - -resource "aws_instance" "bar" { - foo = "${module.child.num}" -} diff --git a/internal/terraform/testdata/plan-module-var-with-default-value/inner/main.tf b/internal/terraform/testdata/plan-module-var-with-default-value/inner/main.tf deleted file mode 100644 index 5b5cf6cdfc5e..000000000000 --- a/internal/terraform/testdata/plan-module-var-with-default-value/inner/main.tf +++ /dev/null @@ -1,12 +0,0 @@ -variable "im_a_string" { - type = string -} - -variable "service_region_ami" { - type = map(string) - default = { - us-east-1 = "ami-e4c9db8e" - } -} - -resource "null_resource" "noop" {} diff --git a/internal/terraform/testdata/plan-module-var-with-default-value/main.tf b/internal/terraform/testdata/plan-module-var-with-default-value/main.tf deleted file mode 100644 index 96b27418a03f..000000000000 --- a/internal/terraform/testdata/plan-module-var-with-default-value/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "null_resource" "noop" {} - -module "test" { - source = "./inner" - - im_a_string = "hello" -} diff --git a/internal/terraform/testdata/plan-module-var/child/main.tf b/internal/terraform/testdata/plan-module-var/child/main.tf deleted file mode 100644 index c7b1d283e3a0..000000000000 --- a/internal/terraform/testdata/plan-module-var/child/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "foo" { - num = "2" -} - -output "num" { - value = "${aws_instance.foo.num}" -} diff --git a/internal/terraform/testdata/plan-module-var/main.tf b/internal/terraform/testdata/plan-module-var/main.tf deleted file mode 100644 index 942bdba92697..000000000000 --- a/internal/terraform/testdata/plan-module-var/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -module "child" { - source = "./child" -} - -resource "aws_instance" "bar" { - foo = "${module.child.num}" -} diff --git a/internal/terraform/testdata/plan-module-variable-from-splat/main.tf b/internal/terraform/testdata/plan-module-variable-from-splat/main.tf deleted file mode 100644 index be900a3c4a7b..000000000000 --- a/internal/terraform/testdata/plan-module-variable-from-splat/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -module "mod1" { - source = "./mod" - param = ["this", "one", "works"] -} - -module "mod2" { - source = "./mod" - param = [module.mod1.out_from_splat[0]] -} diff --git a/internal/terraform/testdata/plan-module-variable-from-splat/mod/main.tf b/internal/terraform/testdata/plan-module-variable-from-splat/mod/main.tf deleted file mode 100644 index 66127d36b0ab..000000000000 --- a/internal/terraform/testdata/plan-module-variable-from-splat/mod/main.tf +++ /dev/null @@ -1,12 +0,0 @@ -variable "param" { - type = list(string) -} - -resource "aws_instance" "test" { - count = "2" - thing = "doesnt" -} - -output "out_from_splat" { - value = aws_instance.test.*.thing -} diff --git a/internal/terraform/testdata/plan-module-wrong-var-type-nested/inner/main.tf b/internal/terraform/testdata/plan-module-wrong-var-type-nested/inner/main.tf deleted file mode 100644 index dabe507fe57d..000000000000 --- a/internal/terraform/testdata/plan-module-wrong-var-type-nested/inner/main.tf +++ /dev/null @@ -1,13 +0,0 @@ -variable "inner_in" { - type = map(string) - default = { - us-west-1 = "ami-12345" - us-west-2 = "ami-67890" - } -} - -resource "null_resource" "inner_noop" {} - -output "inner_out" { - value = lookup(var.inner_in, "us-west-1") -} diff --git a/internal/terraform/testdata/plan-module-wrong-var-type-nested/main.tf b/internal/terraform/testdata/plan-module-wrong-var-type-nested/main.tf deleted file mode 100644 index 8f9fdcc56510..000000000000 --- a/internal/terraform/testdata/plan-module-wrong-var-type-nested/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -module "middle" { - source = "./middle" -} diff --git a/internal/terraform/testdata/plan-module-wrong-var-type-nested/middle/main.tf b/internal/terraform/testdata/plan-module-wrong-var-type-nested/middle/main.tf deleted file mode 100644 index eb989fe93608..000000000000 --- a/internal/terraform/testdata/plan-module-wrong-var-type-nested/middle/main.tf +++ /dev/null @@ -1,19 +0,0 @@ -variable "middle_in" { - type = map(string) - default = { - eu-west-1 = "ami-12345" - eu-west-2 = "ami-67890" - } -} - -module "inner" { - source = "../inner" - - inner_in = "hello" -} - -resource "null_resource" "middle_noop" {} - -output "middle_out" { - value = lookup(var.middle_in, "us-west-1") -} diff --git a/internal/terraform/testdata/plan-module-wrong-var-type/inner/main.tf b/internal/terraform/testdata/plan-module-wrong-var-type/inner/main.tf deleted file mode 100644 index 7782d1b844d4..000000000000 --- a/internal/terraform/testdata/plan-module-wrong-var-type/inner/main.tf +++ /dev/null @@ -1,13 +0,0 @@ -variable "map_in" { - type = map(string) - - default = { - us-west-1 = "ami-12345" - us-west-2 = "ami-67890" - } -} - -// We have to reference it so it isn't pruned -output "output" { - value = var.map_in -} diff --git a/internal/terraform/testdata/plan-module-wrong-var-type/main.tf b/internal/terraform/testdata/plan-module-wrong-var-type/main.tf deleted file mode 100644 index 5a39cd5d5aeb..000000000000 --- a/internal/terraform/testdata/plan-module-wrong-var-type/main.tf +++ /dev/null @@ -1,10 +0,0 @@ -variable "input" { - type = string - default = "hello world" -} - -module "test" { - source = "./inner" - - map_in = var.input -} diff --git a/internal/terraform/testdata/plan-modules-expand/child/main.tf b/internal/terraform/testdata/plan-modules-expand/child/main.tf deleted file mode 100644 index 612478f79d5d..000000000000 --- a/internal/terraform/testdata/plan-modules-expand/child/main.tf +++ /dev/null @@ -1,12 +0,0 @@ -variable "foo" {} -variable "bar" {} - -resource "aws_instance" "foo" { - count = 2 - num = var.foo - bar = "baz" #var.bar -} - -output "out" { - value = aws_instance.foo[0].id -} diff --git a/internal/terraform/testdata/plan-modules-expand/main.tf b/internal/terraform/testdata/plan-modules-expand/main.tf deleted file mode 100644 index 023709596c6c..000000000000 --- a/internal/terraform/testdata/plan-modules-expand/main.tf +++ /dev/null @@ -1,29 +0,0 @@ -locals { - val = 2 - bar = "baz" - m = { - "a" = "b" - } -} - -variable "myvar" { - default = "baz" -} - -module "count_child" { - count = local.val - foo = count.index - bar = var.myvar - source = "./child" -} - -module "for_each_child" { - for_each = aws_instance.foo - foo = 2 - bar = each.key - source = "./child" -} - -resource "aws_instance" "foo" { - for_each = local.m -} diff --git a/internal/terraform/testdata/plan-modules-remove-provisioners/main.tf b/internal/terraform/testdata/plan-modules-remove-provisioners/main.tf deleted file mode 100644 index ce9a38866464..000000000000 --- a/internal/terraform/testdata/plan-modules-remove-provisioners/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -resource "aws_instance" "top" {} - -# module "test" { -# source = "./parent" -# } diff --git a/internal/terraform/testdata/plan-modules-remove-provisioners/parent/child/main.tf b/internal/terraform/testdata/plan-modules-remove-provisioners/parent/child/main.tf deleted file mode 100644 index b626e60c824e..000000000000 --- a/internal/terraform/testdata/plan-modules-remove-provisioners/parent/child/main.tf +++ /dev/null @@ -1,2 +0,0 @@ -resource "aws_instance" "foo" { -} diff --git a/internal/terraform/testdata/plan-modules-remove-provisioners/parent/main.tf b/internal/terraform/testdata/plan-modules-remove-provisioners/parent/main.tf deleted file mode 100644 index fbc1aa09c1e3..000000000000 --- a/internal/terraform/testdata/plan-modules-remove-provisioners/parent/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -module "childone" { - source = "./child" -} - -module "childtwo" { - source = "./child" -} diff --git a/internal/terraform/testdata/plan-modules-remove/main.tf b/internal/terraform/testdata/plan-modules-remove/main.tf deleted file mode 100644 index 98f5ee87e9f0..000000000000 --- a/internal/terraform/testdata/plan-modules-remove/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_instance" "foo" { - num = "2" -} diff --git a/internal/terraform/testdata/plan-modules/child/main.tf b/internal/terraform/testdata/plan-modules/child/main.tf deleted file mode 100644 index 98f5ee87e9f0..000000000000 --- a/internal/terraform/testdata/plan-modules/child/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_instance" "foo" { - num = "2" -} diff --git a/internal/terraform/testdata/plan-modules/main.tf b/internal/terraform/testdata/plan-modules/main.tf deleted file mode 100644 index dcdb236a1d34..000000000000 --- a/internal/terraform/testdata/plan-modules/main.tf +++ /dev/null @@ -1,11 +0,0 @@ -module "child" { - source = "./child" -} - -resource "aws_instance" "foo" { - num = "2" -} - -resource "aws_instance" "bar" { - foo = "${aws_instance.foo.num}" -} diff --git a/internal/terraform/testdata/plan-orphan/main.tf b/internal/terraform/testdata/plan-orphan/main.tf deleted file mode 100644 index 98f5ee87e9f0..000000000000 --- a/internal/terraform/testdata/plan-orphan/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_instance" "foo" { - num = "2" -} diff --git a/internal/terraform/testdata/plan-path-var/main.tf b/internal/terraform/testdata/plan-path-var/main.tf deleted file mode 100644 index 13012569882d..000000000000 --- a/internal/terraform/testdata/plan-path-var/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -resource "aws_instance" "foo" { - cwd = "${path.cwd}/barpath" - module = "${path.module}/foopath" - root = "${path.root}/barpath" -} diff --git a/internal/terraform/testdata/plan-prevent-destroy-bad/main.tf b/internal/terraform/testdata/plan-prevent-destroy-bad/main.tf deleted file mode 100644 index 19077c1a6512..000000000000 --- a/internal/terraform/testdata/plan-prevent-destroy-bad/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "foo" { - require_new = "yes" - - lifecycle { - prevent_destroy = true - } -} diff --git a/internal/terraform/testdata/plan-prevent-destroy-count-bad/main.tf b/internal/terraform/testdata/plan-prevent-destroy-count-bad/main.tf deleted file mode 100644 index 818f93e70203..000000000000 --- a/internal/terraform/testdata/plan-prevent-destroy-count-bad/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -resource "aws_instance" "foo" { - count = "1" - current = "${count.index}" - - lifecycle { - prevent_destroy = true - } -} diff --git a/internal/terraform/testdata/plan-prevent-destroy-count-good/main.tf b/internal/terraform/testdata/plan-prevent-destroy-count-good/main.tf deleted file mode 100644 index b6b479078501..000000000000 --- a/internal/terraform/testdata/plan-prevent-destroy-count-good/main.tf +++ /dev/null @@ -1,4 +0,0 @@ -resource "aws_instance" "foo" { - count = "1" - current = "${count.index}" -} diff --git a/internal/terraform/testdata/plan-prevent-destroy-good/main.tf b/internal/terraform/testdata/plan-prevent-destroy-good/main.tf deleted file mode 100644 index a88b9e3e101c..000000000000 --- a/internal/terraform/testdata/plan-prevent-destroy-good/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -resource "aws_instance" "foo" { - lifecycle { - prevent_destroy = true - } -} diff --git a/internal/terraform/testdata/plan-provider/main.tf b/internal/terraform/testdata/plan-provider/main.tf deleted file mode 100644 index 8010f70aef9e..000000000000 --- a/internal/terraform/testdata/plan-provider/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -variable "foo" {} - -provider "aws" { - foo = "${var.foo}" -} - -resource "aws_instance" "bar" {} diff --git a/internal/terraform/testdata/plan-provisioner-cycle/main.tf b/internal/terraform/testdata/plan-provisioner-cycle/main.tf deleted file mode 100644 index ed65c0918caa..000000000000 --- a/internal/terraform/testdata/plan-provisioner-cycle/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "foo" { - count = 3 - - provisioner "local-exec" { - command = "echo ${aws_instance.foo.0.id} ${aws_instance.foo.1.id} ${aws_instance.foo.2.id}" - } -} diff --git a/internal/terraform/testdata/plan-required-output/main.tf b/internal/terraform/testdata/plan-required-output/main.tf deleted file mode 100644 index 227b5c1530ce..000000000000 --- a/internal/terraform/testdata/plan-required-output/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "test_resource" "root" { - required = module.mod.object.id -} - -module "mod" { - source = "./mod" -} diff --git a/internal/terraform/testdata/plan-required-output/mod/main.tf b/internal/terraform/testdata/plan-required-output/mod/main.tf deleted file mode 100644 index 772f1645f3e8..000000000000 --- a/internal/terraform/testdata/plan-required-output/mod/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "test_resource" "for_output" { - required = "val" -} - -output "object" { - value = test_resource.for_output -} diff --git a/internal/terraform/testdata/plan-required-whole-mod/main.tf b/internal/terraform/testdata/plan-required-whole-mod/main.tf deleted file mode 100644 index 9deb3c5a162b..000000000000 --- a/internal/terraform/testdata/plan-required-whole-mod/main.tf +++ /dev/null @@ -1,17 +0,0 @@ -resource "test_resource" "root" { - required = local.object.id -} - -locals { - # This indirection is here to force the evaluator to produce the whole - # module object here rather than just fetching the single "object" output. - # This makes this fixture different than plan-required-output, which just - # accesses module.mod.object.id directly and thus visits a different - # codepath in the evaluator. - mod = module.mod - object = local.mod.object -} - -module "mod" { - source = "./mod" -} diff --git a/internal/terraform/testdata/plan-required-whole-mod/mod/main.tf b/internal/terraform/testdata/plan-required-whole-mod/mod/main.tf deleted file mode 100644 index 772f1645f3e8..000000000000 --- a/internal/terraform/testdata/plan-required-whole-mod/mod/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "test_resource" "for_output" { - required = "val" -} - -output "object" { - value = test_resource.for_output -} diff --git a/internal/terraform/testdata/plan-requires-replace/main.tf b/internal/terraform/testdata/plan-requires-replace/main.tf deleted file mode 100644 index 23cee56b3b81..000000000000 --- a/internal/terraform/testdata/plan-requires-replace/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "test_thing" "foo" { - v = "goodbye" -} diff --git a/internal/terraform/testdata/plan-self-ref-multi-all/main.tf b/internal/terraform/testdata/plan-self-ref-multi-all/main.tf deleted file mode 100644 index d3a9857f7bd3..000000000000 --- a/internal/terraform/testdata/plan-self-ref-multi-all/main.tf +++ /dev/null @@ -1,4 +0,0 @@ -resource "aws_instance" "web" { - foo = "${aws_instance.web.*.foo}" - count = 4 -} diff --git a/internal/terraform/testdata/plan-self-ref-multi/main.tf b/internal/terraform/testdata/plan-self-ref-multi/main.tf deleted file mode 100644 index 5b27cac7150f..000000000000 --- a/internal/terraform/testdata/plan-self-ref-multi/main.tf +++ /dev/null @@ -1,4 +0,0 @@ -resource "aws_instance" "web" { - foo = "${aws_instance.web.0.foo}" - count = 4 -} diff --git a/internal/terraform/testdata/plan-self-ref/main.tf b/internal/terraform/testdata/plan-self-ref/main.tf deleted file mode 100644 index f2bf91d77bf9..000000000000 --- a/internal/terraform/testdata/plan-self-ref/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_instance" "web" { - foo = "${aws_instance.web.foo}" -} diff --git a/internal/terraform/testdata/plan-shadow-uuid/main.tf b/internal/terraform/testdata/plan-shadow-uuid/main.tf deleted file mode 100644 index 2b6ec72a0015..000000000000 --- a/internal/terraform/testdata/plan-shadow-uuid/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_instance" "test" { - value = "${uuid()}" -} diff --git a/internal/terraform/testdata/plan-taint-ignore-changes/main.tf b/internal/terraform/testdata/plan-taint-ignore-changes/main.tf deleted file mode 100644 index ff95d6596dc2..000000000000 --- a/internal/terraform/testdata/plan-taint-ignore-changes/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "foo" { - vars = "foo" - - lifecycle { - ignore_changes = ["vars"] - } -} diff --git a/internal/terraform/testdata/plan-taint-interpolated-count/main.tf b/internal/terraform/testdata/plan-taint-interpolated-count/main.tf deleted file mode 100644 index 91d8b65c81c5..000000000000 --- a/internal/terraform/testdata/plan-taint-interpolated-count/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -variable "instance_count" { - default = 3 -} - -resource "aws_instance" "foo" { - count = "${var.instance_count}" -} diff --git a/internal/terraform/testdata/plan-taint/main.tf b/internal/terraform/testdata/plan-taint/main.tf deleted file mode 100644 index 1b6cdae67b0e..000000000000 --- a/internal/terraform/testdata/plan-taint/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "foo" { - num = "2" -} - -resource "aws_instance" "bar" { - foo = "${aws_instance.foo.num}" -} diff --git a/internal/terraform/testdata/plan-targeted-cross-module/A/main.tf b/internal/terraform/testdata/plan-targeted-cross-module/A/main.tf deleted file mode 100644 index 4c014aa22343..000000000000 --- a/internal/terraform/testdata/plan-targeted-cross-module/A/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "foo" { - foo = "bar" -} - -output "value" { - value = "${aws_instance.foo.id}" -} diff --git a/internal/terraform/testdata/plan-targeted-cross-module/B/main.tf b/internal/terraform/testdata/plan-targeted-cross-module/B/main.tf deleted file mode 100644 index c3aeb7b76e39..000000000000 --- a/internal/terraform/testdata/plan-targeted-cross-module/B/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -variable "input" {} - -resource "aws_instance" "bar" { - foo = "${var.input}" -} diff --git a/internal/terraform/testdata/plan-targeted-cross-module/main.tf b/internal/terraform/testdata/plan-targeted-cross-module/main.tf deleted file mode 100644 index e6a83b2a02b9..000000000000 --- a/internal/terraform/testdata/plan-targeted-cross-module/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -module "A" { - source = "./A" -} - -module "B" { - source = "./B" - input = "${module.A.value}" -} diff --git a/internal/terraform/testdata/plan-targeted-module-orphan/main.tf b/internal/terraform/testdata/plan-targeted-module-orphan/main.tf deleted file mode 100644 index 2b33fedaed10..000000000000 --- a/internal/terraform/testdata/plan-targeted-module-orphan/main.tf +++ /dev/null @@ -1,6 +0,0 @@ -# Once opon a time, there was a child module here -/* -module "child" { - source = "./child" -} -*/ diff --git a/internal/terraform/testdata/plan-targeted-module-untargeted-variable/child/main.tf b/internal/terraform/testdata/plan-targeted-module-untargeted-variable/child/main.tf deleted file mode 100644 index f7b424b8415f..000000000000 --- a/internal/terraform/testdata/plan-targeted-module-untargeted-variable/child/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -variable "id" {} - -resource "aws_instance" "mod" { - value = "${var.id}" -} diff --git a/internal/terraform/testdata/plan-targeted-module-untargeted-variable/main.tf b/internal/terraform/testdata/plan-targeted-module-untargeted-variable/main.tf deleted file mode 100644 index 90e44dceba60..000000000000 --- a/internal/terraform/testdata/plan-targeted-module-untargeted-variable/main.tf +++ /dev/null @@ -1,12 +0,0 @@ -resource "aws_instance" "blue" { } -resource "aws_instance" "green" { } - -module "blue_mod" { - source = "./child" - id = "${aws_instance.blue.id}" -} - -module "green_mod" { - source = "./child" - id = "${aws_instance.green.id}" -} diff --git a/internal/terraform/testdata/plan-targeted-module-with-provider/child1/main.tf b/internal/terraform/testdata/plan-targeted-module-with-provider/child1/main.tf deleted file mode 100644 index c9aaff5f724d..000000000000 --- a/internal/terraform/testdata/plan-targeted-module-with-provider/child1/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -variable "key" {} - -provider "null" { - key = "${var.key}" -} - -resource "null_resource" "foo" {} diff --git a/internal/terraform/testdata/plan-targeted-module-with-provider/child2/main.tf b/internal/terraform/testdata/plan-targeted-module-with-provider/child2/main.tf deleted file mode 100644 index c9aaff5f724d..000000000000 --- a/internal/terraform/testdata/plan-targeted-module-with-provider/child2/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -variable "key" {} - -provider "null" { - key = "${var.key}" -} - -resource "null_resource" "foo" {} diff --git a/internal/terraform/testdata/plan-targeted-module-with-provider/main.tf b/internal/terraform/testdata/plan-targeted-module-with-provider/main.tf deleted file mode 100644 index 0fa7bcffdd7d..000000000000 --- a/internal/terraform/testdata/plan-targeted-module-with-provider/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -module "child1" { - source = "./child1" - key = "value" -} - -module "child2" { - source = "./child2" - key = "value" -} diff --git a/internal/terraform/testdata/plan-targeted-orphan/main.tf b/internal/terraform/testdata/plan-targeted-orphan/main.tf deleted file mode 100644 index f2020858b148..000000000000 --- a/internal/terraform/testdata/plan-targeted-orphan/main.tf +++ /dev/null @@ -1,6 +0,0 @@ -# This resource was previously "created" and the fixture represents -# it being destroyed subsequently - -/*resource "aws_instance" "orphan" {*/ - /*foo = "bar"*/ -/*}*/ diff --git a/internal/terraform/testdata/plan-targeted-over-ten/main.tf b/internal/terraform/testdata/plan-targeted-over-ten/main.tf deleted file mode 100644 index 1c7bc8769e07..000000000000 --- a/internal/terraform/testdata/plan-targeted-over-ten/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_instance" "foo" { - count = 13 -} diff --git a/internal/terraform/testdata/plan-targeted/main.tf b/internal/terraform/testdata/plan-targeted/main.tf deleted file mode 100644 index ab00a845fa58..000000000000 --- a/internal/terraform/testdata/plan-targeted/main.tf +++ /dev/null @@ -1,12 +0,0 @@ -resource "aws_instance" "foo" { - num = "2" -} - -resource "aws_instance" "bar" { - foo = aws_instance.foo.num -} - -module "mod" { - source = "./mod" - count = 1 -} diff --git a/internal/terraform/testdata/plan-targeted/mod/main.tf b/internal/terraform/testdata/plan-targeted/mod/main.tf deleted file mode 100644 index 98f5ee87e9f0..000000000000 --- a/internal/terraform/testdata/plan-targeted/mod/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_instance" "foo" { - num = "2" -} diff --git a/internal/terraform/testdata/plan-untargeted-resource-output/main.tf b/internal/terraform/testdata/plan-untargeted-resource-output/main.tf deleted file mode 100644 index 9d4a1c882d18..000000000000 --- a/internal/terraform/testdata/plan-untargeted-resource-output/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -module "mod" { - source = "./mod" -} - - -resource "aws_instance" "c" { - name = "${module.mod.output}" -} diff --git a/internal/terraform/testdata/plan-untargeted-resource-output/mod/main.tf b/internal/terraform/testdata/plan-untargeted-resource-output/mod/main.tf deleted file mode 100644 index dd6d791cba4f..000000000000 --- a/internal/terraform/testdata/plan-untargeted-resource-output/mod/main.tf +++ /dev/null @@ -1,15 +0,0 @@ -locals { - one = 1 -} - -resource "aws_instance" "a" { - count = "${local.one}" -} - -resource "aws_instance" "b" { - count = "${local.one}" -} - -output "output" { - value = "${join("", coalescelist(aws_instance.a.*.id, aws_instance.b.*.id))}" -} diff --git a/internal/terraform/testdata/plan-var-list-err/main.tf b/internal/terraform/testdata/plan-var-list-err/main.tf deleted file mode 100644 index 6303064c9f64..000000000000 --- a/internal/terraform/testdata/plan-var-list-err/main.tf +++ /dev/null @@ -1,16 +0,0 @@ -provider "aws" { - access_key = "a" - secret_key = "b" - region = "us-east-1" -} - -resource "aws_instance" "foo" { - ami = "ami-foo" - instance_type = "t2.micro" - security_groups = "${aws_security_group.foo.name}" -} - -resource "aws_security_group" "foo" { - name = "foobar" - description = "foobar" -} diff --git a/internal/terraform/testdata/plan-variable-sensitivity-module/child/main.tf b/internal/terraform/testdata/plan-variable-sensitivity-module/child/main.tf deleted file mode 100644 index e34751aa9b65..000000000000 --- a/internal/terraform/testdata/plan-variable-sensitivity-module/child/main.tf +++ /dev/null @@ -1,13 +0,0 @@ -variable "foo" { - type = string -} - -// "bar" is defined as sensitive by both the parent and the child -variable "bar" { - sensitive = true -} - -resource "aws_instance" "foo" { - foo = var.foo - value = var.bar -} diff --git a/internal/terraform/testdata/plan-variable-sensitivity-module/main.tf b/internal/terraform/testdata/plan-variable-sensitivity-module/main.tf deleted file mode 100644 index 69bdbb4cbed8..000000000000 --- a/internal/terraform/testdata/plan-variable-sensitivity-module/main.tf +++ /dev/null @@ -1,14 +0,0 @@ -variable "sensitive_var" { - default = "foo" - sensitive = true -} - -variable "another_var" { - sensitive = true -} - -module "child" { - source = "./child" - foo = var.sensitive_var - bar = var.another_var -} diff --git a/internal/terraform/testdata/plan-variable-sensitivity/main.tf b/internal/terraform/testdata/plan-variable-sensitivity/main.tf deleted file mode 100644 index 00a4b1ef9ee3..000000000000 --- a/internal/terraform/testdata/plan-variable-sensitivity/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -variable "sensitive_var" { - default = "foo" - sensitive = true -} - -resource "aws_instance" "foo" { - foo = var.sensitive_var -} \ No newline at end of file diff --git a/internal/terraform/testdata/provider-meta-data-set/main.tf b/internal/terraform/testdata/provider-meta-data-set/main.tf deleted file mode 100644 index ef7acd957b38..000000000000 --- a/internal/terraform/testdata/provider-meta-data-set/main.tf +++ /dev/null @@ -1,13 +0,0 @@ -data "test_data_source" "foo" { - foo = "bar" -} - -terraform { - provider_meta "test" { - baz = "quux" - } -} - -module "my_module" { - source = "./my-module" -} diff --git a/internal/terraform/testdata/provider-meta-data-set/my-module/main.tf b/internal/terraform/testdata/provider-meta-data-set/my-module/main.tf deleted file mode 100644 index 61a97706935f..000000000000 --- a/internal/terraform/testdata/provider-meta-data-set/my-module/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -data "test_file" "foo" { - id = "bar" -} - -terraform { - provider_meta "test" { - baz = "quux-submodule" - } -} diff --git a/internal/terraform/testdata/provider-meta-data-unset/main.tf b/internal/terraform/testdata/provider-meta-data-unset/main.tf deleted file mode 100644 index c4091f37b13b..000000000000 --- a/internal/terraform/testdata/provider-meta-data-unset/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -data "test_data_source" "foo" { - foo = "bar" -} - -module "my_module" { - source = "./my-module" -} diff --git a/internal/terraform/testdata/provider-meta-data-unset/my-module/main.tf b/internal/terraform/testdata/provider-meta-data-unset/my-module/main.tf deleted file mode 100644 index 7e0ea46b6b7d..000000000000 --- a/internal/terraform/testdata/provider-meta-data-unset/my-module/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -data "test_file" "foo" { - id = "bar" -} diff --git a/internal/terraform/testdata/provider-meta-set/main.tf b/internal/terraform/testdata/provider-meta-set/main.tf deleted file mode 100644 index a3e9f804bee8..000000000000 --- a/internal/terraform/testdata/provider-meta-set/main.tf +++ /dev/null @@ -1,13 +0,0 @@ -resource "test_instance" "bar" { - foo = "bar" -} - -terraform { - provider_meta "test" { - baz = "quux" - } -} - -module "my_module" { - source = "./my-module" -} diff --git a/internal/terraform/testdata/provider-meta-set/my-module/main.tf b/internal/terraform/testdata/provider-meta-set/my-module/main.tf deleted file mode 100644 index 2a89dd51f34b..000000000000 --- a/internal/terraform/testdata/provider-meta-set/my-module/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -resource "test_resource" "bar" { - value = "bar" -} - -terraform { - provider_meta "test" { - baz = "quux-submodule" - } -} diff --git a/internal/terraform/testdata/provider-meta-unset/main.tf b/internal/terraform/testdata/provider-meta-unset/main.tf deleted file mode 100644 index 0ae85d39fa27..000000000000 --- a/internal/terraform/testdata/provider-meta-unset/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "test_instance" "bar" { - foo = "bar" -} - -module "my_module" { - source = "./my-module" -} diff --git a/internal/terraform/testdata/provider-meta-unset/my-module/main.tf b/internal/terraform/testdata/provider-meta-unset/my-module/main.tf deleted file mode 100644 index ec9701f95606..000000000000 --- a/internal/terraform/testdata/provider-meta-unset/my-module/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "test_resource" "bar" { - value = "bar" -} diff --git a/internal/terraform/testdata/provider-with-locals/main.tf b/internal/terraform/testdata/provider-with-locals/main.tf deleted file mode 100644 index 3a7db0f87727..000000000000 --- a/internal/terraform/testdata/provider-with-locals/main.tf +++ /dev/null @@ -1,11 +0,0 @@ -provider "aws" { - region = "${local.foo}" -} - -locals { - foo = "bar" -} - -resource "aws_instance" "foo" { - value = "${local.foo}" -} diff --git a/internal/terraform/testdata/refresh-basic/main.tf b/internal/terraform/testdata/refresh-basic/main.tf deleted file mode 100644 index 64cbf6236650..000000000000 --- a/internal/terraform/testdata/refresh-basic/main.tf +++ /dev/null @@ -1 +0,0 @@ -resource "aws_instance" "web" {} diff --git a/internal/terraform/testdata/refresh-data-count/refresh-data-count.tf b/internal/terraform/testdata/refresh-data-count/refresh-data-count.tf deleted file mode 100644 index ccabdb2c689c..000000000000 --- a/internal/terraform/testdata/refresh-data-count/refresh-data-count.tf +++ /dev/null @@ -1,6 +0,0 @@ -resource "test" "foo" { -} - -data "test" "foo" { - count = length(test.foo.things) -} diff --git a/internal/terraform/testdata/refresh-data-module-var/child/main.tf b/internal/terraform/testdata/refresh-data-module-var/child/main.tf deleted file mode 100644 index 64d21beda045..000000000000 --- a/internal/terraform/testdata/refresh-data-module-var/child/main.tf +++ /dev/null @@ -1,6 +0,0 @@ -variable "key" {} - -data "aws_data_source" "foo" { - id = "${var.key}" -} - diff --git a/internal/terraform/testdata/refresh-data-module-var/main.tf b/internal/terraform/testdata/refresh-data-module-var/main.tf deleted file mode 100644 index a371831bd231..000000000000 --- a/internal/terraform/testdata/refresh-data-module-var/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -resource "aws_instance" "A" { - foo = "bar" -} - -module "child" { - source = "./child" - key = "${aws_instance.A.id}" -} diff --git a/internal/terraform/testdata/refresh-data-ref-data/main.tf b/internal/terraform/testdata/refresh-data-ref-data/main.tf deleted file mode 100644 index 5512be233216..000000000000 --- a/internal/terraform/testdata/refresh-data-ref-data/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -data "null_data_source" "foo" { - foo = "yes" -} - -data "null_data_source" "bar" { - bar = "${data.null_data_source.foo.foo}" -} diff --git a/internal/terraform/testdata/refresh-data-resource-basic/main.tf b/internal/terraform/testdata/refresh-data-resource-basic/main.tf deleted file mode 100644 index cb16d9f34140..000000000000 --- a/internal/terraform/testdata/refresh-data-resource-basic/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -data "null_data_source" "testing" { - inputs = { - test = "yes" - } -} diff --git a/internal/terraform/testdata/refresh-dynamic/main.tf b/internal/terraform/testdata/refresh-dynamic/main.tf deleted file mode 100644 index 5c857a2f459e..000000000000 --- a/internal/terraform/testdata/refresh-dynamic/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "test_instance" "foo" { - dynamic = {} -} diff --git a/internal/terraform/testdata/refresh-module-computed-var/child/main.tf b/internal/terraform/testdata/refresh-module-computed-var/child/main.tf deleted file mode 100644 index 38260d6373c5..000000000000 --- a/internal/terraform/testdata/refresh-module-computed-var/child/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -variable "value" {} - -output "value" { - value = "${var.value}" -} diff --git a/internal/terraform/testdata/refresh-module-computed-var/main.tf b/internal/terraform/testdata/refresh-module-computed-var/main.tf deleted file mode 100644 index a8573327b154..000000000000 --- a/internal/terraform/testdata/refresh-module-computed-var/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -module "child" { - source = "./child" - value = "${join(" ", aws_instance.test.*.id)}" -} - -resource "aws_instance" "test" { - value = "yes" -} diff --git a/internal/terraform/testdata/refresh-module-input-computed-output/child/main.tf b/internal/terraform/testdata/refresh-module-input-computed-output/child/main.tf deleted file mode 100644 index ebc1e3ffc142..000000000000 --- a/internal/terraform/testdata/refresh-module-input-computed-output/child/main.tf +++ /dev/null @@ -1,11 +0,0 @@ -variable "input" { - type = string -} - -resource "aws_instance" "foo" { - foo = var.input -} - -output "foo" { - value = aws_instance.foo.foo -} diff --git a/internal/terraform/testdata/refresh-module-input-computed-output/main.tf b/internal/terraform/testdata/refresh-module-input-computed-output/main.tf deleted file mode 100644 index 5827a5da25e2..000000000000 --- a/internal/terraform/testdata/refresh-module-input-computed-output/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -module "child" { - input = aws_instance.bar.foo - source = "./child" -} - -resource "aws_instance" "bar" { - compute = "foo" -} diff --git a/internal/terraform/testdata/refresh-module-orphan/child/grandchild/main.tf b/internal/terraform/testdata/refresh-module-orphan/child/grandchild/main.tf deleted file mode 100644 index 942e93dbc485..000000000000 --- a/internal/terraform/testdata/refresh-module-orphan/child/grandchild/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_instance" "baz" {} - -output "id" { value = "${aws_instance.baz.id}" } diff --git a/internal/terraform/testdata/refresh-module-orphan/child/main.tf b/internal/terraform/testdata/refresh-module-orphan/child/main.tf deleted file mode 100644 index 7c3fc842f34d..000000000000 --- a/internal/terraform/testdata/refresh-module-orphan/child/main.tf +++ /dev/null @@ -1,10 +0,0 @@ -module "grandchild" { - source = "./grandchild" -} - -resource "aws_instance" "bar" { - grandchildid = "${module.grandchild.id}" -} - -output "id" { value = "${aws_instance.bar.id}" } -output "grandchild_id" { value = "${module.grandchild.id}" } diff --git a/internal/terraform/testdata/refresh-module-orphan/main.tf b/internal/terraform/testdata/refresh-module-orphan/main.tf deleted file mode 100644 index 244374d9d162..000000000000 --- a/internal/terraform/testdata/refresh-module-orphan/main.tf +++ /dev/null @@ -1,10 +0,0 @@ -/* -module "child" { - source = "./child" -} - -resource "aws_instance" "bar" { - childid = "${module.child.id}" - grandchildid = "${module.child.grandchild_id}" -} -*/ diff --git a/internal/terraform/testdata/refresh-module-var-module/bar/main.tf b/internal/terraform/testdata/refresh-module-var-module/bar/main.tf deleted file mode 100644 index 46ea37f14f29..000000000000 --- a/internal/terraform/testdata/refresh-module-var-module/bar/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -variable "value" {} - -resource "aws_instance" "bar" {} diff --git a/internal/terraform/testdata/refresh-module-var-module/foo/main.tf b/internal/terraform/testdata/refresh-module-var-module/foo/main.tf deleted file mode 100644 index 2ee798058d3f..000000000000 --- a/internal/terraform/testdata/refresh-module-var-module/foo/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -output "output" { - value = "${aws_instance.foo.foo}" -} - -resource "aws_instance" "foo" { - compute = "foo" -} diff --git a/internal/terraform/testdata/refresh-module-var-module/main.tf b/internal/terraform/testdata/refresh-module-var-module/main.tf deleted file mode 100644 index 76775e3e6d04..000000000000 --- a/internal/terraform/testdata/refresh-module-var-module/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -module "foo" { - source = "./foo" -} - -module "bar" { - source = "./bar" - value = "${module.foo.output}" -} diff --git a/internal/terraform/testdata/refresh-modules/child/main.tf b/internal/terraform/testdata/refresh-modules/child/main.tf deleted file mode 100644 index 64cbf6236650..000000000000 --- a/internal/terraform/testdata/refresh-modules/child/main.tf +++ /dev/null @@ -1 +0,0 @@ -resource "aws_instance" "web" {} diff --git a/internal/terraform/testdata/refresh-modules/main.tf b/internal/terraform/testdata/refresh-modules/main.tf deleted file mode 100644 index 6b4520ec0f47..000000000000 --- a/internal/terraform/testdata/refresh-modules/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -module "child" { - source = "./child" -} - -resource "aws_instance" "web" {} diff --git a/internal/terraform/testdata/refresh-no-state/main.tf b/internal/terraform/testdata/refresh-no-state/main.tf deleted file mode 100644 index 76c0f87671c2..000000000000 --- a/internal/terraform/testdata/refresh-no-state/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -output "foo" { - value = "" -} diff --git a/internal/terraform/testdata/refresh-output-partial/main.tf b/internal/terraform/testdata/refresh-output-partial/main.tf deleted file mode 100644 index 36ce289a34b7..000000000000 --- a/internal/terraform/testdata/refresh-output-partial/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "foo" {} - -resource "aws_instance" "web" {} - -output "foo" { - value = "${aws_instance.web.foo}" -} diff --git a/internal/terraform/testdata/refresh-output/main.tf b/internal/terraform/testdata/refresh-output/main.tf deleted file mode 100644 index 42a01bd5ca19..000000000000 --- a/internal/terraform/testdata/refresh-output/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -resource "aws_instance" "web" {} - -output "foo" { - value = "${aws_instance.web.foo}" -} diff --git a/internal/terraform/testdata/refresh-schema-upgrade/main.tf b/internal/terraform/testdata/refresh-schema-upgrade/main.tf deleted file mode 100644 index ee0590e3c2d2..000000000000 --- a/internal/terraform/testdata/refresh-schema-upgrade/main.tf +++ /dev/null @@ -1,2 +0,0 @@ -resource "test_thing" "bar" { -} diff --git a/internal/terraform/testdata/refresh-targeted-count/main.tf b/internal/terraform/testdata/refresh-targeted-count/main.tf deleted file mode 100644 index f564b629c1ac..000000000000 --- a/internal/terraform/testdata/refresh-targeted-count/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -resource "aws_vpc" "metoo" {} -resource "aws_instance" "notme" { } -resource "aws_instance" "me" { - vpc_id = "${aws_vpc.metoo.id}" - count = 3 -} -resource "aws_elb" "meneither" { - instances = ["${aws_instance.me.*.id}"] -} diff --git a/internal/terraform/testdata/refresh-targeted/main.tf b/internal/terraform/testdata/refresh-targeted/main.tf deleted file mode 100644 index 3a76184647fc..000000000000 --- a/internal/terraform/testdata/refresh-targeted/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -resource "aws_vpc" "metoo" {} -resource "aws_instance" "notme" { } -resource "aws_instance" "me" { - vpc_id = "${aws_vpc.metoo.id}" -} -resource "aws_elb" "meneither" { - instances = ["${aws_instance.me.*.id}"] -} diff --git a/internal/terraform/testdata/refresh-unknown-provider/main.tf b/internal/terraform/testdata/refresh-unknown-provider/main.tf deleted file mode 100644 index 8a29fddd0863..000000000000 --- a/internal/terraform/testdata/refresh-unknown-provider/main.tf +++ /dev/null @@ -1,4 +0,0 @@ -resource "unknown_instance" "foo" { - num = "2" - compute = "foo" -} diff --git a/internal/terraform/testdata/refresh-vars/main.tf b/internal/terraform/testdata/refresh-vars/main.tf deleted file mode 100644 index 86cd6ace3723..000000000000 --- a/internal/terraform/testdata/refresh-vars/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -resource "aws_instance" "web" {} - -resource "aws_instance" "db" { - ami = "${aws_instance.web.id}" -} diff --git a/internal/terraform/testdata/static-validate-refs/static-validate-refs.tf b/internal/terraform/testdata/static-validate-refs/static-validate-refs.tf deleted file mode 100644 index 3667a4e11f35..000000000000 --- a/internal/terraform/testdata/static-validate-refs/static-validate-refs.tf +++ /dev/null @@ -1,23 +0,0 @@ -terraform { - required_providers { - boop = { - source = "foobar/beep" # intentional mismatch between local name and type - } - } -} - -resource "aws_instance" "no_count" { -} - -resource "aws_instance" "count" { - count = 1 -} - -resource "boop_instance" "yep" { -} - -resource "boop_whatever" "nope" { -} - -data "beep" "boop" { -} diff --git a/internal/terraform/testdata/transform-cbd-destroy-edge-both-count/main.tf b/internal/terraform/testdata/transform-cbd-destroy-edge-both-count/main.tf deleted file mode 100644 index c19e78eaa2f3..000000000000 --- a/internal/terraform/testdata/transform-cbd-destroy-edge-both-count/main.tf +++ /dev/null @@ -1,11 +0,0 @@ -resource "test_object" "A" { - count = 2 - lifecycle { - create_before_destroy = true - } -} - -resource "test_object" "B" { - count = 2 - test_string = test_object.A[*].test_string[count.index] -} diff --git a/internal/terraform/testdata/transform-cbd-destroy-edge-count/main.tf b/internal/terraform/testdata/transform-cbd-destroy-edge-count/main.tf deleted file mode 100644 index 775900fcdd82..000000000000 --- a/internal/terraform/testdata/transform-cbd-destroy-edge-count/main.tf +++ /dev/null @@ -1,10 +0,0 @@ -resource "test_object" "A" { - lifecycle { - create_before_destroy = true - } -} - -resource "test_object" "B" { - count = 2 - test_string = test_object.A.test_string -} diff --git a/internal/terraform/testdata/transform-config-mode-data/main.tf b/internal/terraform/testdata/transform-config-mode-data/main.tf deleted file mode 100644 index 3c3e7e50d553..000000000000 --- a/internal/terraform/testdata/transform-config-mode-data/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -data "aws_ami" "foo" {} - -resource "aws_instance" "web" {} diff --git a/internal/terraform/testdata/transform-destroy-cbd-edge-basic/main.tf b/internal/terraform/testdata/transform-destroy-cbd-edge-basic/main.tf deleted file mode 100644 index a17d8b4e35c0..000000000000 --- a/internal/terraform/testdata/transform-destroy-cbd-edge-basic/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -resource "test_object" "A" { - lifecycle { - create_before_destroy = true - } -} - -resource "test_object" "B" { - test_string = "${test_object.A.id}" -} diff --git a/internal/terraform/testdata/transform-destroy-cbd-edge-multi/main.tf b/internal/terraform/testdata/transform-destroy-cbd-edge-multi/main.tf deleted file mode 100644 index 964bc44cfd87..000000000000 --- a/internal/terraform/testdata/transform-destroy-cbd-edge-multi/main.tf +++ /dev/null @@ -1,15 +0,0 @@ -resource "test_object" "A" { - lifecycle { - create_before_destroy = true - } -} - -resource "test_object" "B" { - lifecycle { - create_before_destroy = true - } -} - -resource "test_object" "C" { - test_string = "${test_object.A.id}-${test_object.B.id}" -} diff --git a/internal/terraform/testdata/transform-destroy-edge-basic/main.tf b/internal/terraform/testdata/transform-destroy-edge-basic/main.tf deleted file mode 100644 index 8afeda4feed2..000000000000 --- a/internal/terraform/testdata/transform-destroy-edge-basic/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -resource "test_object" "A" {} - -resource "test_object" "B" { - test_string = "${test_object.A.test_string}" -} diff --git a/internal/terraform/testdata/transform-destroy-edge-module-only/child/main.tf b/internal/terraform/testdata/transform-destroy-edge-module-only/child/main.tf deleted file mode 100644 index 242bb3359041..000000000000 --- a/internal/terraform/testdata/transform-destroy-edge-module-only/child/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -resource "test_object" "a" {} - -resource "test_object" "b" { - test_string = "${test_object.a.test_string}" -} - -resource "test_object" "c" { - test_string = "${test_object.b.test_string}" -} diff --git a/internal/terraform/testdata/transform-destroy-edge-module-only/main.tf b/internal/terraform/testdata/transform-destroy-edge-module-only/main.tf deleted file mode 100644 index 919351443d22..000000000000 --- a/internal/terraform/testdata/transform-destroy-edge-module-only/main.tf +++ /dev/null @@ -1,4 +0,0 @@ -module "child" { - source = "./child" - count = 2 -} diff --git a/internal/terraform/testdata/transform-destroy-edge-module/child/main.tf b/internal/terraform/testdata/transform-destroy-edge-module/child/main.tf deleted file mode 100644 index 337bbe754e70..000000000000 --- a/internal/terraform/testdata/transform-destroy-edge-module/child/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "test_object" "b" { - test_string = "foo" -} - -output "output" { - value = "${test_object.b.test_string}" -} diff --git a/internal/terraform/testdata/transform-destroy-edge-module/main.tf b/internal/terraform/testdata/transform-destroy-edge-module/main.tf deleted file mode 100644 index 2a42635e4f5f..000000000000 --- a/internal/terraform/testdata/transform-destroy-edge-module/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "test_object" "a" { - test_string = "${module.child.output}" -} - -module "child" { - source = "./child" -} diff --git a/internal/terraform/testdata/transform-destroy-edge-multi/main.tf b/internal/terraform/testdata/transform-destroy-edge-multi/main.tf deleted file mode 100644 index 3474bf60a422..000000000000 --- a/internal/terraform/testdata/transform-destroy-edge-multi/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -resource "test_object" "A" {} - -resource "test_object" "B" { - test_string = "${test_object.A.test_string}" -} - -resource "test_object" "C" { - test_string = "${test_object.B.test_string}" -} diff --git a/internal/terraform/testdata/transform-destroy-edge-self-ref/main.tf b/internal/terraform/testdata/transform-destroy-edge-self-ref/main.tf deleted file mode 100644 index d91e024c4758..000000000000 --- a/internal/terraform/testdata/transform-destroy-edge-self-ref/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -resource "test" "A" { - provisioner "foo" { - command = "${test.A.id}" - } -} diff --git a/internal/terraform/testdata/transform-module-var-basic/child/main.tf b/internal/terraform/testdata/transform-module-var-basic/child/main.tf deleted file mode 100644 index 53f3cd731d65..000000000000 --- a/internal/terraform/testdata/transform-module-var-basic/child/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -variable "value" {} - -output "result" { - value = "${var.value}" -} diff --git a/internal/terraform/testdata/transform-module-var-basic/main.tf b/internal/terraform/testdata/transform-module-var-basic/main.tf deleted file mode 100644 index 0adb513f10ef..000000000000 --- a/internal/terraform/testdata/transform-module-var-basic/main.tf +++ /dev/null @@ -1,4 +0,0 @@ -module "child" { - source = "./child" - value = "foo" -} diff --git a/internal/terraform/testdata/transform-module-var-nested/child/child/main.tf b/internal/terraform/testdata/transform-module-var-nested/child/child/main.tf deleted file mode 100644 index 53f3cd731d65..000000000000 --- a/internal/terraform/testdata/transform-module-var-nested/child/child/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -variable "value" {} - -output "result" { - value = "${var.value}" -} diff --git a/internal/terraform/testdata/transform-module-var-nested/child/main.tf b/internal/terraform/testdata/transform-module-var-nested/child/main.tf deleted file mode 100644 index b8c7f0bac242..000000000000 --- a/internal/terraform/testdata/transform-module-var-nested/child/main.tf +++ /dev/null @@ -1,6 +0,0 @@ -variable "value" {} - -module "child" { - source = "./child" - value = "${var.value}" -} diff --git a/internal/terraform/testdata/transform-module-var-nested/main.tf b/internal/terraform/testdata/transform-module-var-nested/main.tf deleted file mode 100644 index 2c20f1979270..000000000000 --- a/internal/terraform/testdata/transform-module-var-nested/main.tf +++ /dev/null @@ -1,4 +0,0 @@ -module "child" { - source = "./child" - value = "foo" -} diff --git a/internal/terraform/testdata/transform-orphan-basic/main.tf b/internal/terraform/testdata/transform-orphan-basic/main.tf deleted file mode 100644 index 64cbf6236650..000000000000 --- a/internal/terraform/testdata/transform-orphan-basic/main.tf +++ /dev/null @@ -1 +0,0 @@ -resource "aws_instance" "web" {} diff --git a/internal/terraform/testdata/transform-orphan-count-empty/main.tf b/internal/terraform/testdata/transform-orphan-count-empty/main.tf deleted file mode 100644 index e8045d6fce1c..000000000000 --- a/internal/terraform/testdata/transform-orphan-count-empty/main.tf +++ /dev/null @@ -1 +0,0 @@ -# Purposefully empty diff --git a/internal/terraform/testdata/transform-orphan-count/main.tf b/internal/terraform/testdata/transform-orphan-count/main.tf deleted file mode 100644 index acef373b35de..000000000000 --- a/internal/terraform/testdata/transform-orphan-count/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_instance" "foo" { - count = 3 -} diff --git a/internal/terraform/testdata/transform-orphan-modules/main.tf b/internal/terraform/testdata/transform-orphan-modules/main.tf deleted file mode 100644 index 919f140bba6b..000000000000 --- a/internal/terraform/testdata/transform-orphan-modules/main.tf +++ /dev/null @@ -1 +0,0 @@ -resource "aws_instance" "foo" {} diff --git a/internal/terraform/testdata/transform-provider-basic/main.tf b/internal/terraform/testdata/transform-provider-basic/main.tf deleted file mode 100644 index 8a44e1dcbb58..000000000000 --- a/internal/terraform/testdata/transform-provider-basic/main.tf +++ /dev/null @@ -1,2 +0,0 @@ -provider "aws" {} -resource "aws_instance" "web" {} diff --git a/internal/terraform/testdata/transform-provider-fqns-module/child/main.tf b/internal/terraform/testdata/transform-provider-fqns-module/child/main.tf deleted file mode 100644 index 5c56b7693975..000000000000 --- a/internal/terraform/testdata/transform-provider-fqns-module/child/main.tf +++ /dev/null @@ -1,11 +0,0 @@ -terraform { - required_providers { - your-aws = { - source = "hashicorp/aws" - } - } -} - -resource "aws_instance" "web" { - provider = "your-aws" -} diff --git a/internal/terraform/testdata/transform-provider-fqns-module/main.tf b/internal/terraform/testdata/transform-provider-fqns-module/main.tf deleted file mode 100644 index dd582c0634b0..000000000000 --- a/internal/terraform/testdata/transform-provider-fqns-module/main.tf +++ /dev/null @@ -1,11 +0,0 @@ -terraform { - required_providers { - my-aws = { - source = "hashicorp/aws" - } - } -} - -resource "aws_instance" "web" { - provider = "my-aws" -} diff --git a/internal/terraform/testdata/transform-provider-fqns/main.tf b/internal/terraform/testdata/transform-provider-fqns/main.tf deleted file mode 100644 index dd582c0634b0..000000000000 --- a/internal/terraform/testdata/transform-provider-fqns/main.tf +++ /dev/null @@ -1,11 +0,0 @@ -terraform { - required_providers { - my-aws = { - source = "hashicorp/aws" - } - } -} - -resource "aws_instance" "web" { - provider = "my-aws" -} diff --git a/internal/terraform/testdata/transform-provider-grandchild-inherit/child/grandchild/main.tf b/internal/terraform/testdata/transform-provider-grandchild-inherit/child/grandchild/main.tf deleted file mode 100644 index 58363ef0c08a..000000000000 --- a/internal/terraform/testdata/transform-provider-grandchild-inherit/child/grandchild/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -provider "aws" { - alias = "baz" -} - -resource "aws_instance" "baz" { - provider = "aws.baz" -} diff --git a/internal/terraform/testdata/transform-provider-grandchild-inherit/child/main.tf b/internal/terraform/testdata/transform-provider-grandchild-inherit/child/main.tf deleted file mode 100644 index 7ec80343de70..000000000000 --- a/internal/terraform/testdata/transform-provider-grandchild-inherit/child/main.tf +++ /dev/null @@ -1,10 +0,0 @@ -provider "aws" { - alias = "bar" -} - -module "grandchild" { - source = "./grandchild" - providers = { - aws.baz = aws.bar - } -} diff --git a/internal/terraform/testdata/transform-provider-grandchild-inherit/main.tf b/internal/terraform/testdata/transform-provider-grandchild-inherit/main.tf deleted file mode 100644 index cb9a2f9de982..000000000000 --- a/internal/terraform/testdata/transform-provider-grandchild-inherit/main.tf +++ /dev/null @@ -1,11 +0,0 @@ -provider "aws" { - alias = "foo" - value = "config" -} - -module "child" { - source = "./child" - providers = { - aws.bar = aws.foo - } -} diff --git a/internal/terraform/testdata/transform-provider-inherit/child/main.tf b/internal/terraform/testdata/transform-provider-inherit/child/main.tf deleted file mode 100644 index b1f07068461c..000000000000 --- a/internal/terraform/testdata/transform-provider-inherit/child/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -provider "aws" { - alias = "bar" -} - -resource "aws_instance" "thing" { - provider = aws.bar -} diff --git a/internal/terraform/testdata/transform-provider-inherit/main.tf b/internal/terraform/testdata/transform-provider-inherit/main.tf deleted file mode 100644 index cb9a2f9de982..000000000000 --- a/internal/terraform/testdata/transform-provider-inherit/main.tf +++ /dev/null @@ -1,11 +0,0 @@ -provider "aws" { - alias = "foo" - value = "config" -} - -module "child" { - source = "./child" - providers = { - aws.bar = aws.foo - } -} diff --git a/internal/terraform/testdata/transform-provider-missing-grandchild/main.tf b/internal/terraform/testdata/transform-provider-missing-grandchild/main.tf deleted file mode 100644 index 385674a891ed..000000000000 --- a/internal/terraform/testdata/transform-provider-missing-grandchild/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -module "sub" { - source = "./sub" -} diff --git a/internal/terraform/testdata/transform-provider-missing-grandchild/sub/main.tf b/internal/terraform/testdata/transform-provider-missing-grandchild/sub/main.tf deleted file mode 100644 index 65adf2d1ccc2..000000000000 --- a/internal/terraform/testdata/transform-provider-missing-grandchild/sub/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -provider "foo" {} - -module "subsub" { - source = "./subsub" -} diff --git a/internal/terraform/testdata/transform-provider-missing-grandchild/sub/subsub/main.tf b/internal/terraform/testdata/transform-provider-missing-grandchild/sub/subsub/main.tf deleted file mode 100644 index fd865a52501e..000000000000 --- a/internal/terraform/testdata/transform-provider-missing-grandchild/sub/subsub/main.tf +++ /dev/null @@ -1,2 +0,0 @@ -resource "foo_instance" "one" {} -resource "bar_instance" "two" {} diff --git a/internal/terraform/testdata/transform-provider-missing/main.tf b/internal/terraform/testdata/transform-provider-missing/main.tf deleted file mode 100644 index 976f3e5af843..000000000000 --- a/internal/terraform/testdata/transform-provider-missing/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -provider "aws" {} -resource "aws_instance" "web" {} -resource "foo_instance" "web" {} diff --git a/internal/terraform/testdata/transform-provider-prune/main.tf b/internal/terraform/testdata/transform-provider-prune/main.tf deleted file mode 100644 index 986f8840bf92..000000000000 --- a/internal/terraform/testdata/transform-provider-prune/main.tf +++ /dev/null @@ -1,2 +0,0 @@ -provider "aws" {} -resource "foo_instance" "web" {} diff --git a/internal/terraform/testdata/transform-provisioner-basic/main.tf b/internal/terraform/testdata/transform-provisioner-basic/main.tf deleted file mode 100644 index 3898ac4dbe1d..000000000000 --- a/internal/terraform/testdata/transform-provisioner-basic/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_instance" "web" { - provisioner "shell" {} -} diff --git a/internal/terraform/testdata/transform-provisioner-module/child/main.tf b/internal/terraform/testdata/transform-provisioner-module/child/main.tf deleted file mode 100644 index 51b29c72a082..000000000000 --- a/internal/terraform/testdata/transform-provisioner-module/child/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_instance" "foo" { - provisioner "shell" {} -} diff --git a/internal/terraform/testdata/transform-provisioner-module/main.tf b/internal/terraform/testdata/transform-provisioner-module/main.tf deleted file mode 100644 index a825a449eb1b..000000000000 --- a/internal/terraform/testdata/transform-provisioner-module/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "foo" { - provisioner "shell" {} -} - -module "child" { - source = "./child" -} diff --git a/internal/terraform/testdata/transform-root-basic/main.tf b/internal/terraform/testdata/transform-root-basic/main.tf deleted file mode 100644 index e4ff4b3e9057..000000000000 --- a/internal/terraform/testdata/transform-root-basic/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -provider "aws" {} -resource "aws_instance" "foo" {} - -provider "do" {} -resource "do_droplet" "bar" {} diff --git a/internal/terraform/testdata/transform-targets-basic/main.tf b/internal/terraform/testdata/transform-targets-basic/main.tf deleted file mode 100644 index 47edc2a7fef7..000000000000 --- a/internal/terraform/testdata/transform-targets-basic/main.tf +++ /dev/null @@ -1,22 +0,0 @@ -resource "aws_vpc" "me" {} - -resource "aws_subnet" "me" { - depends_on = [ - aws_vpc.me, - ] -} - -resource "aws_instance" "me" { - depends_on = [ - aws_subnet.me, - ] -} - -resource "aws_vpc" "notme" {} -resource "aws_subnet" "notme" {} -resource "aws_instance" "notme" {} -resource "aws_instance" "notmeeither" { - depends_on = [ - aws_instance.me, - ] -} diff --git a/internal/terraform/testdata/transform-targets-downstream/child/child.tf b/internal/terraform/testdata/transform-targets-downstream/child/child.tf deleted file mode 100644 index 6548b794930b..000000000000 --- a/internal/terraform/testdata/transform-targets-downstream/child/child.tf +++ /dev/null @@ -1,14 +0,0 @@ -resource "aws_instance" "foo" { -} - -module "grandchild" { - source = "./grandchild" -} - -output "id" { - value = "${aws_instance.foo.id}" -} - -output "grandchild_id" { - value = "${module.grandchild.id}" -} diff --git a/internal/terraform/testdata/transform-targets-downstream/child/grandchild/grandchild.tf b/internal/terraform/testdata/transform-targets-downstream/child/grandchild/grandchild.tf deleted file mode 100644 index 3ad8fd077013..000000000000 --- a/internal/terraform/testdata/transform-targets-downstream/child/grandchild/grandchild.tf +++ /dev/null @@ -1,6 +0,0 @@ -resource "aws_instance" "foo" { -} - -output "id" { - value = "${aws_instance.foo.id}" -} diff --git a/internal/terraform/testdata/transform-targets-downstream/main.tf b/internal/terraform/testdata/transform-targets-downstream/main.tf deleted file mode 100644 index b732fdad7ea8..000000000000 --- a/internal/terraform/testdata/transform-targets-downstream/main.tf +++ /dev/null @@ -1,18 +0,0 @@ -resource "aws_instance" "foo" { -} - -module "child" { - source = "./child" -} - -output "root_id" { - value = "${aws_instance.foo.id}" -} - -output "child_id" { - value = "${module.child.id}" -} - -output "grandchild_id" { - value = "${module.child.grandchild_id}" -} diff --git a/internal/terraform/testdata/transform-trans-reduce-basic/main.tf b/internal/terraform/testdata/transform-trans-reduce-basic/main.tf deleted file mode 100644 index 4fb97c7a7b9a..000000000000 --- a/internal/terraform/testdata/transform-trans-reduce-basic/main.tf +++ /dev/null @@ -1,10 +0,0 @@ -resource "aws_instance" "A" {} - -resource "aws_instance" "B" { - A = "${aws_instance.A.id}" -} - -resource "aws_instance" "C" { - A = "${aws_instance.A.id}" - B = "${aws_instance.B.id}" -} diff --git a/internal/terraform/testdata/update-resource-provider/main.tf b/internal/terraform/testdata/update-resource-provider/main.tf deleted file mode 100644 index 6c082d540815..000000000000 --- a/internal/terraform/testdata/update-resource-provider/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -provider "aws" { - alias = "foo" -} - -resource "aws_instance" "bar" { - provider = "aws.foo" -} diff --git a/internal/terraform/testdata/validate-bad-count/main.tf b/internal/terraform/testdata/validate-bad-count/main.tf deleted file mode 100644 index a582e5ee39ec..000000000000 --- a/internal/terraform/testdata/validate-bad-count/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_instance" "foo" { - count = "${list}" -} diff --git a/internal/terraform/testdata/validate-bad-module-output/child/main.tf b/internal/terraform/testdata/validate-bad-module-output/child/main.tf deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/internal/terraform/testdata/validate-bad-module-output/main.tf b/internal/terraform/testdata/validate-bad-module-output/main.tf deleted file mode 100644 index bda34f51a4e2..000000000000 --- a/internal/terraform/testdata/validate-bad-module-output/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -module "child" { - source = "./child" -} - -resource "aws_instance" "bar" { - foo = "${module.child.bad}" -} diff --git a/internal/terraform/testdata/validate-bad-pc/main.tf b/internal/terraform/testdata/validate-bad-pc/main.tf deleted file mode 100644 index 70ad701e6cbc..000000000000 --- a/internal/terraform/testdata/validate-bad-pc/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -provider "aws" { - foo = "bar" -} - -resource "aws_instance" "test" {} diff --git a/internal/terraform/testdata/validate-bad-prov-conf/main.tf b/internal/terraform/testdata/validate-bad-prov-conf/main.tf deleted file mode 100644 index af12124b3fa7..000000000000 --- a/internal/terraform/testdata/validate-bad-prov-conf/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -provider "aws" { - foo = "bar" -} - -resource "aws_instance" "test" { - provisioner "shell" { - test_string = "foo" - } -} diff --git a/internal/terraform/testdata/validate-bad-prov-connection/main.tf b/internal/terraform/testdata/validate-bad-prov-connection/main.tf deleted file mode 100644 index 550714ff1d1a..000000000000 --- a/internal/terraform/testdata/validate-bad-prov-connection/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -resource "aws_instance" "foo" { - provisioner "shell" { - test_string = "test" - connection { - user = "test" - } - } -} diff --git a/internal/terraform/testdata/validate-bad-rc/main.tf b/internal/terraform/testdata/validate-bad-rc/main.tf deleted file mode 100644 index 152a23e0d864..000000000000 --- a/internal/terraform/testdata/validate-bad-rc/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_instance" "test" { - foo = "bar" -} diff --git a/internal/terraform/testdata/validate-bad-resource-connection/main.tf b/internal/terraform/testdata/validate-bad-resource-connection/main.tf deleted file mode 100644 index 46a16717591c..000000000000 --- a/internal/terraform/testdata/validate-bad-resource-connection/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -resource "aws_instance" "foo" { - connection { - user = "test" - } - provisioner "shell" { - test_string = "test" - } -} diff --git a/internal/terraform/testdata/validate-bad-resource-count/main.tf b/internal/terraform/testdata/validate-bad-resource-count/main.tf deleted file mode 100644 index f852a447eadb..000000000000 --- a/internal/terraform/testdata/validate-bad-resource-count/main.tf +++ /dev/null @@ -1,22 +0,0 @@ -// a resource named "aws_security_groups" does not exist in the schema -variable "sg_ports" { - type = list(number) - description = "List of ingress ports" - default = [8200, 8201, 8300, 9200, 9500] -} - - -resource "aws_security_groups" "dynamicsg" { - name = "dynamicsg" - description = "Ingress for Vault" - - dynamic "ingress" { - for_each = var.sg_ports - content { - from_port = ingress.value - to_port = ingress.value - protocol = "tcp" - cidr_blocks = ["0.0.0.0/0"] - } - } -} diff --git a/internal/terraform/testdata/validate-bad-var/main.tf b/internal/terraform/testdata/validate-bad-var/main.tf deleted file mode 100644 index 50028453d416..000000000000 --- a/internal/terraform/testdata/validate-bad-var/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "foo" { - num = "2" -} - -resource "aws_instance" "bar" { - foo = "${var.foo}" -} diff --git a/internal/terraform/testdata/validate-computed-in-function/main.tf b/internal/terraform/testdata/validate-computed-in-function/main.tf deleted file mode 100644 index 504e19426128..000000000000 --- a/internal/terraform/testdata/validate-computed-in-function/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -data "aws_data_source" "foo" { - optional_attr = "value" -} - -resource "aws_instance" "bar" { - attr = "${length(data.aws_data_source.foo.computed)}" -} diff --git a/internal/terraform/testdata/validate-computed-module-var-ref/dest/main.tf b/internal/terraform/testdata/validate-computed-module-var-ref/dest/main.tf deleted file mode 100644 index 44095ea75422..000000000000 --- a/internal/terraform/testdata/validate-computed-module-var-ref/dest/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -variable "destin" { } - -resource "aws_instance" "dest" { - attr = "${var.destin}" -} diff --git a/internal/terraform/testdata/validate-computed-module-var-ref/main.tf b/internal/terraform/testdata/validate-computed-module-var-ref/main.tf deleted file mode 100644 index d7c799cc8b64..000000000000 --- a/internal/terraform/testdata/validate-computed-module-var-ref/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -module "source" { - source = "./source" -} - -module "dest" { - source = "./dest" - destin = "${module.source.sourceout}" -} diff --git a/internal/terraform/testdata/validate-computed-module-var-ref/source/main.tf b/internal/terraform/testdata/validate-computed-module-var-ref/source/main.tf deleted file mode 100644 index d2edc9e0f170..000000000000 --- a/internal/terraform/testdata/validate-computed-module-var-ref/source/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_instance" "source" { - attr = "foo" -} - -output "sourceout" { - value = "${aws_instance.source.attr}" -} diff --git a/internal/terraform/testdata/validate-computed-var/main.tf b/internal/terraform/testdata/validate-computed-var/main.tf deleted file mode 100644 index 81acf7cfaa9d..000000000000 --- a/internal/terraform/testdata/validate-computed-var/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -provider "aws" { - value = test_instance.foo.id -} - -resource "aws_instance" "bar" {} - -resource "test_instance" "foo" { - value = "yes" -} diff --git a/internal/terraform/testdata/validate-count-computed/main.tf b/internal/terraform/testdata/validate-count-computed/main.tf deleted file mode 100644 index e7de125f2263..000000000000 --- a/internal/terraform/testdata/validate-count-computed/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -data "aws_data_source" "foo" { - compute = "value" -} - -resource "aws_instance" "bar" { - count = "${data.aws_data_source.foo.value}" -} diff --git a/internal/terraform/testdata/validate-count-negative/main.tf b/internal/terraform/testdata/validate-count-negative/main.tf deleted file mode 100644 index d5bb046533d9..000000000000 --- a/internal/terraform/testdata/validate-count-negative/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_instance" "test" { - count = "-5" -} diff --git a/internal/terraform/testdata/validate-count-variable/main.tf b/internal/terraform/testdata/validate-count-variable/main.tf deleted file mode 100644 index 9c892ac2eac8..000000000000 --- a/internal/terraform/testdata/validate-count-variable/main.tf +++ /dev/null @@ -1,6 +0,0 @@ -variable "foo" {} - -resource "aws_instance" "foo" { - foo = "foo" - count = "${var.foo}" -} diff --git a/internal/terraform/testdata/validate-good-module/child/main.tf b/internal/terraform/testdata/validate-good-module/child/main.tf deleted file mode 100644 index 17d8c60a7722..000000000000 --- a/internal/terraform/testdata/validate-good-module/child/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -output "good" { - value = "great" -} diff --git a/internal/terraform/testdata/validate-good-module/main.tf b/internal/terraform/testdata/validate-good-module/main.tf deleted file mode 100644 index 439d20210c49..000000000000 --- a/internal/terraform/testdata/validate-good-module/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -module "child" { - source = "./child" -} - -resource "aws_instance" "bar" { - foo = "${module.child.good}" -} diff --git a/internal/terraform/testdata/validate-good/main.tf b/internal/terraform/testdata/validate-good/main.tf deleted file mode 100644 index fe44019b7dad..000000000000 --- a/internal/terraform/testdata/validate-good/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -resource "aws_instance" "foo" { - num = "2" - foo = "bar" -} - -resource "aws_instance" "bar" { - foo = "bar" -} diff --git a/internal/terraform/testdata/validate-module-bad-rc/child/main.tf b/internal/terraform/testdata/validate-module-bad-rc/child/main.tf deleted file mode 100644 index 919f140bba6b..000000000000 --- a/internal/terraform/testdata/validate-module-bad-rc/child/main.tf +++ /dev/null @@ -1 +0,0 @@ -resource "aws_instance" "foo" {} diff --git a/internal/terraform/testdata/validate-module-bad-rc/main.tf b/internal/terraform/testdata/validate-module-bad-rc/main.tf deleted file mode 100644 index 0f6991c536ca..000000000000 --- a/internal/terraform/testdata/validate-module-bad-rc/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -module "child" { - source = "./child" -} diff --git a/internal/terraform/testdata/validate-module-deps-cycle/a/main.tf b/internal/terraform/testdata/validate-module-deps-cycle/a/main.tf deleted file mode 100644 index 3d3b01634eb6..000000000000 --- a/internal/terraform/testdata/validate-module-deps-cycle/a/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -resource "aws_instance" "a" { } - -output "output" { - value = "${aws_instance.a.id}" -} diff --git a/internal/terraform/testdata/validate-module-deps-cycle/b/main.tf b/internal/terraform/testdata/validate-module-deps-cycle/b/main.tf deleted file mode 100644 index 0f8fc9116e63..000000000000 --- a/internal/terraform/testdata/validate-module-deps-cycle/b/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -variable "input" {} - -resource "aws_instance" "b" { - id = "${var.input}" -} diff --git a/internal/terraform/testdata/validate-module-deps-cycle/main.tf b/internal/terraform/testdata/validate-module-deps-cycle/main.tf deleted file mode 100644 index 11ddb64bfa7f..000000000000 --- a/internal/terraform/testdata/validate-module-deps-cycle/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -module "a" { - source = "./a" -} - -module "b" { - source = "./b" - input = "${module.a.output}" -} diff --git a/internal/terraform/testdata/validate-module-pc-inherit-unused/child/main.tf b/internal/terraform/testdata/validate-module-pc-inherit-unused/child/main.tf deleted file mode 100644 index 919f140bba6b..000000000000 --- a/internal/terraform/testdata/validate-module-pc-inherit-unused/child/main.tf +++ /dev/null @@ -1 +0,0 @@ -resource "aws_instance" "foo" {} diff --git a/internal/terraform/testdata/validate-module-pc-inherit-unused/main.tf b/internal/terraform/testdata/validate-module-pc-inherit-unused/main.tf deleted file mode 100644 index 32c8a38f1e6f..000000000000 --- a/internal/terraform/testdata/validate-module-pc-inherit-unused/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -module "child" { - source = "./child" -} - -provider "aws" { - foo = "set" -} diff --git a/internal/terraform/testdata/validate-module-pc-inherit/child/main.tf b/internal/terraform/testdata/validate-module-pc-inherit/child/main.tf deleted file mode 100644 index 37189c1ffb66..000000000000 --- a/internal/terraform/testdata/validate-module-pc-inherit/child/main.tf +++ /dev/null @@ -1,3 +0,0 @@ -provider "aws" {} - -resource "aws_instance" "foo" {} diff --git a/internal/terraform/testdata/validate-module-pc-inherit/main.tf b/internal/terraform/testdata/validate-module-pc-inherit/main.tf deleted file mode 100644 index 8976f4aa9f10..000000000000 --- a/internal/terraform/testdata/validate-module-pc-inherit/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -module "child" { - source = "./child" -} - -provider "aws" { - set = true -} - -resource "aws_instance" "foo" {} diff --git a/internal/terraform/testdata/validate-module-pc-vars/child/main.tf b/internal/terraform/testdata/validate-module-pc-vars/child/main.tf deleted file mode 100644 index 380cd465a398..000000000000 --- a/internal/terraform/testdata/validate-module-pc-vars/child/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -variable "value" {} - -provider "aws" { - foo = var.value -} - -resource "aws_instance" "foo" {} diff --git a/internal/terraform/testdata/validate-module-pc-vars/main.tf b/internal/terraform/testdata/validate-module-pc-vars/main.tf deleted file mode 100644 index 5e239b406652..000000000000 --- a/internal/terraform/testdata/validate-module-pc-vars/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -variable "provider_var" {} - -module "child" { - source = "./child" - - value = var.provider_var -} diff --git a/internal/terraform/testdata/validate-required-provider-config/main.tf b/internal/terraform/testdata/validate-required-provider-config/main.tf deleted file mode 100644 index 898a23fdf251..000000000000 --- a/internal/terraform/testdata/validate-required-provider-config/main.tf +++ /dev/null @@ -1,20 +0,0 @@ -# This test verifies that the provider local name, local config and fqn map -# together properly when the local name does not match the type. - -terraform { - required_providers { - arbitrary = { - source = "hashicorp/aws" - } - } -} - -# hashicorp/test has required provider config attributes. This "arbitrary" -# provider configuration block should map to hashicorp/test. -provider "arbitrary" { - required_attribute = "bloop" -} - -resource "aws_instance" "test" { - provider = "arbitrary" -} diff --git a/internal/terraform/testdata/validate-required-var/main.tf b/internal/terraform/testdata/validate-required-var/main.tf deleted file mode 100644 index bd55ea11bf75..000000000000 --- a/internal/terraform/testdata/validate-required-var/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -variable "foo" {} - -resource "aws_instance" "web" { - ami = "${var.foo}" -} diff --git a/internal/terraform/testdata/validate-sensitive-provisioner-config/main.tf b/internal/terraform/testdata/validate-sensitive-provisioner-config/main.tf deleted file mode 100644 index 88a37275a835..000000000000 --- a/internal/terraform/testdata/validate-sensitive-provisioner-config/main.tf +++ /dev/null @@ -1,11 +0,0 @@ -variable "secret" { - type = string - default = " password123" - sensitive = true -} - -resource "aws_instance" "foo" { - provisioner "test" { - test_string = var.secret - } -} diff --git a/internal/terraform/testdata/validate-skipped-pc-empty/main.tf b/internal/terraform/testdata/validate-skipped-pc-empty/main.tf deleted file mode 100644 index 1ad9ade8948f..000000000000 --- a/internal/terraform/testdata/validate-skipped-pc-empty/main.tf +++ /dev/null @@ -1 +0,0 @@ -resource "aws_instance" "test" {} diff --git a/internal/terraform/testdata/validate-targeted/main.tf b/internal/terraform/testdata/validate-targeted/main.tf deleted file mode 100644 index a1e847d9a0e4..000000000000 --- a/internal/terraform/testdata/validate-targeted/main.tf +++ /dev/null @@ -1,9 +0,0 @@ -resource "aws_instance" "foo" { - num = "2" - provisioner "shell" {} -} - -resource "aws_instance" "bar" { - foo = "bar" - provisioner "shell" {} -} diff --git a/internal/terraform/testdata/validate-var-no-default-explicit-type/main.tf b/internal/terraform/testdata/validate-var-no-default-explicit-type/main.tf deleted file mode 100644 index 5953eab4da98..000000000000 --- a/internal/terraform/testdata/validate-var-no-default-explicit-type/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -variable "maybe_a_map" { - type = map(string) - - // No default -} diff --git a/internal/terraform/testdata/validate-variable-custom-validations-child-sensitive/child/child.tf b/internal/terraform/testdata/validate-variable-custom-validations-child-sensitive/child/child.tf deleted file mode 100644 index 05027f75ade6..000000000000 --- a/internal/terraform/testdata/validate-variable-custom-validations-child-sensitive/child/child.tf +++ /dev/null @@ -1,8 +0,0 @@ -variable "test" { - type = string - - validation { - condition = var.test != "nope" - error_message = "Value must not be \"nope\"." - } -} diff --git a/internal/terraform/testdata/validate-variable-custom-validations-child-sensitive/validate-variable-custom-validations.tf b/internal/terraform/testdata/validate-variable-custom-validations-child-sensitive/validate-variable-custom-validations.tf deleted file mode 100644 index 4f436db11a3d..000000000000 --- a/internal/terraform/testdata/validate-variable-custom-validations-child-sensitive/validate-variable-custom-validations.tf +++ /dev/null @@ -1,10 +0,0 @@ -variable "test" { - sensitive = true - default = "nope" -} - -module "child" { - source = "./child" - - test = var.test -} diff --git a/internal/terraform/testdata/validate-variable-custom-validations-child/child/child.tf b/internal/terraform/testdata/validate-variable-custom-validations-child/child/child.tf deleted file mode 100644 index 05027f75ade6..000000000000 --- a/internal/terraform/testdata/validate-variable-custom-validations-child/child/child.tf +++ /dev/null @@ -1,8 +0,0 @@ -variable "test" { - type = string - - validation { - condition = var.test != "nope" - error_message = "Value must not be \"nope\"." - } -} diff --git a/internal/terraform/testdata/validate-variable-custom-validations-child/validate-variable-custom-validations.tf b/internal/terraform/testdata/validate-variable-custom-validations-child/validate-variable-custom-validations.tf deleted file mode 100644 index 8b8111e675c9..000000000000 --- a/internal/terraform/testdata/validate-variable-custom-validations-child/validate-variable-custom-validations.tf +++ /dev/null @@ -1,5 +0,0 @@ -module "child" { - source = "./child" - - test = "nope" -} diff --git a/internal/terraform/testdata/validate-variable-ref/main.tf b/internal/terraform/testdata/validate-variable-ref/main.tf deleted file mode 100644 index 3bc9860b6029..000000000000 --- a/internal/terraform/testdata/validate-variable-ref/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -variable "foo" {} - -resource "aws_instance" "bar" { - foo = "${var.foo}" -} diff --git a/internal/terraform/testdata/vars-basic-bool/main.tf b/internal/terraform/testdata/vars-basic-bool/main.tf deleted file mode 100644 index 52d90595a275..000000000000 --- a/internal/terraform/testdata/vars-basic-bool/main.tf +++ /dev/null @@ -1,10 +0,0 @@ -// At the time of writing Terraform doesn't formally support a boolean -// type, but historically this has magically worked. Lots of TF code -// relies on this so we test it now. -variable "a" { - default = true -} - -variable "b" { - default = false -} diff --git a/internal/terraform/testdata/vars-basic/main.tf b/internal/terraform/testdata/vars-basic/main.tf deleted file mode 100644 index af3ba5cc6954..000000000000 --- a/internal/terraform/testdata/vars-basic/main.tf +++ /dev/null @@ -1,14 +0,0 @@ -variable "a" { - default = "foo" - type = string -} - -variable "b" { - default = [] - type = list(string) -} - -variable "c" { - default = {} - type = map(string) -} diff --git a/internal/terraform/transform.go b/internal/terraform/transform.go deleted file mode 100644 index 2cc812ffe477..000000000000 --- a/internal/terraform/transform.go +++ /dev/null @@ -1,52 +0,0 @@ -package terraform - -import ( - "log" - - "github.com/hashicorp/terraform/internal/dag" - "github.com/hashicorp/terraform/internal/logging" -) - -// GraphTransformer is the interface that transformers implement. This -// interface is only for transforms that need entire graph visibility. -type GraphTransformer interface { - Transform(*Graph) error -} - -// GraphVertexTransformer is an interface that transforms a single -// Vertex within with graph. This is a specialization of GraphTransformer -// that makes it easy to do vertex replacement. -// -// The GraphTransformer that runs through the GraphVertexTransformers is -// VertexTransformer. -type GraphVertexTransformer interface { - Transform(dag.Vertex) (dag.Vertex, error) -} - -type graphTransformerMulti struct { - Transforms []GraphTransformer -} - -func (t *graphTransformerMulti) Transform(g *Graph) error { - var lastStepStr string - for _, t := range t.Transforms { - log.Printf("[TRACE] (graphTransformerMulti) Executing graph transform %T", t) - if err := t.Transform(g); err != nil { - return err - } - if thisStepStr := g.StringWithNodeTypes(); thisStepStr != lastStepStr { - log.Printf("[TRACE] (graphTransformerMulti) Completed graph transform %T with new graph:\n%s ------", t, logging.Indent(thisStepStr)) - lastStepStr = thisStepStr - } else { - log.Printf("[TRACE] (graphTransformerMulti) Completed graph transform %T (no changes)", t) - } - } - - return nil -} - -// GraphTransformMulti combines multiple graph transformers into a single -// GraphTransformer that runs all the individual graph transformers. -func GraphTransformMulti(ts ...GraphTransformer) GraphTransformer { - return &graphTransformerMulti{Transforms: ts} -} diff --git a/internal/terraform/transform_attach_config_provider.go b/internal/terraform/transform_attach_config_provider.go deleted file mode 100644 index 95153eacedb7..000000000000 --- a/internal/terraform/transform_attach_config_provider.go +++ /dev/null @@ -1,16 +0,0 @@ -package terraform - -import ( - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" -) - -// GraphNodeAttachProvider is an interface that must be implemented by nodes -// that want provider configurations attached. -type GraphNodeAttachProvider interface { - // ProviderName with no module prefix. Example: "aws". - ProviderAddr() addrs.AbsProviderConfig - - // Sets the configuration - AttachProvider(*configs.Provider) -} diff --git a/internal/terraform/transform_attach_config_provider_meta.go b/internal/terraform/transform_attach_config_provider_meta.go deleted file mode 100644 index d79df26fa0a0..000000000000 --- a/internal/terraform/transform_attach_config_provider_meta.go +++ /dev/null @@ -1,15 +0,0 @@ -package terraform - -import ( - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" -) - -// GraphNodeAttachProviderMetaConfigs is an interface that must be implemented -// by nodes that want provider meta configurations attached. -type GraphNodeAttachProviderMetaConfigs interface { - GraphNodeConfigResource - - // Sets the configuration - AttachProviderMetaConfigs(map[addrs.Provider]*configs.ProviderMeta) -} diff --git a/internal/terraform/transform_attach_config_resource.go b/internal/terraform/transform_attach_config_resource.go deleted file mode 100644 index e2468a009961..000000000000 --- a/internal/terraform/transform_attach_config_resource.go +++ /dev/null @@ -1,110 +0,0 @@ -package terraform - -import ( - "log" - - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/dag" -) - -// GraphNodeAttachResourceConfig is an interface that must be implemented by nodes -// that want resource configurations attached. -type GraphNodeAttachResourceConfig interface { - GraphNodeConfigResource - - // Sets the configuration - AttachResourceConfig(*configs.Resource) -} - -// AttachResourceConfigTransformer goes through the graph and attaches -// resource configuration structures to nodes that implement -// GraphNodeAttachManagedResourceConfig or GraphNodeAttachDataResourceConfig. -// -// The attached configuration structures are directly from the configuration. -// If they're going to be modified, a copy should be made. -type AttachResourceConfigTransformer struct { - Config *configs.Config // Config is the root node in the config tree -} - -func (t *AttachResourceConfigTransformer) Transform(g *Graph) error { - - // Go through and find GraphNodeAttachResource - for _, v := range g.Vertices() { - // Only care about GraphNodeAttachResource implementations - arn, ok := v.(GraphNodeAttachResourceConfig) - if !ok { - continue - } - - // Determine what we're looking for - addr := arn.ResourceAddr() - - // Get the configuration. - config := t.Config.Descendent(addr.Module) - if config == nil { - log.Printf("[TRACE] AttachResourceConfigTransformer: %q (%T) has no configuration available", dag.VertexName(v), v) - continue - } - - for _, r := range config.Module.ManagedResources { - rAddr := r.Addr() - - if rAddr != addr.Resource { - // Not the same resource - continue - } - - log.Printf("[TRACE] AttachResourceConfigTransformer: attaching to %q (%T) config from %s", dag.VertexName(v), v, r.DeclRange) - arn.AttachResourceConfig(r) - - // attach the provider_meta info - if gnapmc, ok := v.(GraphNodeAttachProviderMetaConfigs); ok { - log.Printf("[TRACE] AttachResourceConfigTransformer: attaching provider meta configs to %s", dag.VertexName(v)) - if config == nil { - log.Printf("[TRACE] AttachResourceConfigTransformer: no config set on the transformer for %s", dag.VertexName(v)) - continue - } - if config.Module == nil { - log.Printf("[TRACE] AttachResourceConfigTransformer: no module in config for %s", dag.VertexName(v)) - continue - } - if config.Module.ProviderMetas == nil { - log.Printf("[TRACE] AttachResourceConfigTransformer: no provider metas defined for %s", dag.VertexName(v)) - continue - } - gnapmc.AttachProviderMetaConfigs(config.Module.ProviderMetas) - } - } - for _, r := range config.Module.DataResources { - rAddr := r.Addr() - - if rAddr != addr.Resource { - // Not the same resource - continue - } - - log.Printf("[TRACE] AttachResourceConfigTransformer: attaching to %q (%T) config from %#v", dag.VertexName(v), v, r.DeclRange) - arn.AttachResourceConfig(r) - - // attach the provider_meta info - if gnapmc, ok := v.(GraphNodeAttachProviderMetaConfigs); ok { - log.Printf("[TRACE] AttachResourceConfigTransformer: attaching provider meta configs to %s", dag.VertexName(v)) - if config == nil { - log.Printf("[TRACE] AttachResourceConfigTransformer: no config set on the transformer for %s", dag.VertexName(v)) - continue - } - if config.Module == nil { - log.Printf("[TRACE] AttachResourceConfigTransformer: no module in config for %s", dag.VertexName(v)) - continue - } - if config.Module.ProviderMetas == nil { - log.Printf("[TRACE] AttachResourceConfigTransformer: no provider metas defined for %s", dag.VertexName(v)) - continue - } - gnapmc.AttachProviderMetaConfigs(config.Module.ProviderMetas) - } - } - } - - return nil -} diff --git a/internal/terraform/transform_attach_schema.go b/internal/terraform/transform_attach_schema.go deleted file mode 100644 index 8f7a59083348..000000000000 --- a/internal/terraform/transform_attach_schema.go +++ /dev/null @@ -1,109 +0,0 @@ -package terraform - -import ( - "fmt" - "log" - - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/dag" -) - -// GraphNodeAttachResourceSchema is an interface implemented by node types -// that need a resource schema attached. -type GraphNodeAttachResourceSchema interface { - GraphNodeConfigResource - GraphNodeProviderConsumer - - AttachResourceSchema(schema *configschema.Block, version uint64) -} - -// GraphNodeAttachProviderConfigSchema is an interface implemented by node types -// that need a provider configuration schema attached. -type GraphNodeAttachProviderConfigSchema interface { - GraphNodeProvider - - AttachProviderConfigSchema(*configschema.Block) -} - -// GraphNodeAttachProvisionerSchema is an interface implemented by node types -// that need one or more provisioner schemas attached. -type GraphNodeAttachProvisionerSchema interface { - ProvisionedBy() []string - - // SetProvisionerSchema is called during transform for each provisioner - // type returned from ProvisionedBy, providing the configuration schema - // for each provisioner in turn. The implementer should save these for - // later use in evaluating provisioner configuration blocks. - AttachProvisionerSchema(name string, schema *configschema.Block) -} - -// AttachSchemaTransformer finds nodes that implement -// GraphNodeAttachResourceSchema, GraphNodeAttachProviderConfigSchema, or -// GraphNodeAttachProvisionerSchema, looks up the needed schemas for each -// and then passes them to a method implemented by the node. -type AttachSchemaTransformer struct { - Plugins *contextPlugins - Config *configs.Config -} - -func (t *AttachSchemaTransformer) Transform(g *Graph) error { - if t.Plugins == nil { - // Should never happen with a reasonable caller, but we'll return a - // proper error here anyway so that we'll fail gracefully. - return fmt.Errorf("AttachSchemaTransformer used with nil Plugins") - } - - for _, v := range g.Vertices() { - - if tv, ok := v.(GraphNodeAttachResourceSchema); ok { - addr := tv.ResourceAddr() - mode := addr.Resource.Mode - typeName := addr.Resource.Type - providerFqn := tv.Provider() - - schema, version, err := t.Plugins.ResourceTypeSchema(providerFqn, mode, typeName) - if err != nil { - return fmt.Errorf("failed to read schema for %s in %s: %s", addr, providerFqn, err) - } - if schema == nil { - log.Printf("[ERROR] AttachSchemaTransformer: No resource schema available for %s", addr) - continue - } - log.Printf("[TRACE] AttachSchemaTransformer: attaching resource schema to %s", dag.VertexName(v)) - tv.AttachResourceSchema(schema, version) - } - - if tv, ok := v.(GraphNodeAttachProviderConfigSchema); ok { - providerAddr := tv.ProviderAddr() - schema, err := t.Plugins.ProviderConfigSchema(providerAddr.Provider) - if err != nil { - return fmt.Errorf("failed to read provider configuration schema for %s: %s", providerAddr.Provider, err) - } - if schema == nil { - log.Printf("[ERROR] AttachSchemaTransformer: No provider config schema available for %s", providerAddr) - continue - } - log.Printf("[TRACE] AttachSchemaTransformer: attaching provider config schema to %s", dag.VertexName(v)) - tv.AttachProviderConfigSchema(schema) - } - - if tv, ok := v.(GraphNodeAttachProvisionerSchema); ok { - names := tv.ProvisionedBy() - for _, name := range names { - schema, err := t.Plugins.ProvisionerSchema(name) - if err != nil { - return fmt.Errorf("failed to read provisioner configuration schema for %q: %s", name, err) - } - if schema == nil { - log.Printf("[ERROR] AttachSchemaTransformer: No schema available for provisioner %q on %q", name, dag.VertexName(v)) - continue - } - log.Printf("[TRACE] AttachSchemaTransformer: attaching provisioner %q config schema to %s", name, dag.VertexName(v)) - tv.AttachProvisionerSchema(name, schema) - } - } - } - - return nil -} diff --git a/internal/terraform/transform_attach_state.go b/internal/terraform/transform_attach_state.go deleted file mode 100644 index 13694718c20f..000000000000 --- a/internal/terraform/transform_attach_state.go +++ /dev/null @@ -1,68 +0,0 @@ -package terraform - -import ( - "log" - - "github.com/hashicorp/terraform/internal/dag" - "github.com/hashicorp/terraform/internal/states" -) - -// GraphNodeAttachResourceState is an interface that can be implemented -// to request that a ResourceState is attached to the node. -// -// Due to a historical naming inconsistency, the type ResourceState actually -// represents the state for a particular _instance_, while InstanceState -// represents the values for that instance during a particular phase -// (e.g. primary vs. deposed). Consequently, GraphNodeAttachResourceState -// is supported only for nodes that represent resource instances, even though -// the name might suggest it is for containing resources. -type GraphNodeAttachResourceState interface { - GraphNodeResourceInstance - - // Sets the state - AttachResourceState(*states.Resource) -} - -// AttachStateTransformer goes through the graph and attaches -// state to nodes that implement the interfaces above. -type AttachStateTransformer struct { - State *states.State // State is the root state -} - -func (t *AttachStateTransformer) Transform(g *Graph) error { - // If no state, then nothing to do - if t.State == nil { - log.Printf("[DEBUG] Not attaching any node states: overall state is nil") - return nil - } - - for _, v := range g.Vertices() { - // Nodes implement this interface to request state attachment. - an, ok := v.(GraphNodeAttachResourceState) - if !ok { - continue - } - addr := an.ResourceInstanceAddr() - - rs := t.State.Resource(addr.ContainingResource()) - if rs == nil { - log.Printf("[DEBUG] Resource state not found for node %q, instance %s", dag.VertexName(v), addr) - continue - } - - is := rs.Instance(addr.Resource.Key) - if is == nil { - // We don't actually need this here, since we'll attach the whole - // resource state, but we still check because it'd be weird - // for the specific instance we're attaching to not to exist. - log.Printf("[DEBUG] Resource instance state not found for node %q, instance %s", dag.VertexName(v), addr) - continue - } - - // make sure to attach a copy of the state, so instances can modify the - // same ResourceState. - an.AttachResourceState(rs.DeepCopy()) - } - - return nil -} diff --git a/internal/terraform/transform_config.go b/internal/terraform/transform_config.go deleted file mode 100644 index 59fa1eeea9f8..000000000000 --- a/internal/terraform/transform_config.go +++ /dev/null @@ -1,122 +0,0 @@ -package terraform - -import ( - "log" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/dag" -) - -// ConfigTransformer is a GraphTransformer that adds all the resources -// from the configuration to the graph. -// -// The module used to configure this transformer must be the root module. -// -// Only resources are added to the graph. Variables, outputs, and -// providers must be added via other transforms. -// -// Unlike ConfigTransformerOld, this transformer creates a graph with -// all resources including module resources, rather than creating module -// nodes that are then "flattened". -type ConfigTransformer struct { - Concrete ConcreteResourceNodeFunc - - // Module is the module to add resources from. - Config *configs.Config - - // Mode will only add resources that match the given mode - ModeFilter bool - Mode addrs.ResourceMode - - // Do not apply this transformer. - skip bool - - // configuration resources that are to be imported - importTargets []*ImportTarget -} - -func (t *ConfigTransformer) Transform(g *Graph) error { - if t.skip { - return nil - } - - // If no configuration is available, we don't do anything - if t.Config == nil { - return nil - } - - // Start the transformation process - return t.transform(g, t.Config) -} - -func (t *ConfigTransformer) transform(g *Graph, config *configs.Config) error { - // If no config, do nothing - if config == nil { - return nil - } - - // Add our resources - if err := t.transformSingle(g, config); err != nil { - return err - } - - // Transform all the children. - for _, c := range config.Children { - if err := t.transform(g, c); err != nil { - return err - } - } - - return nil -} - -func (t *ConfigTransformer) transformSingle(g *Graph, config *configs.Config) error { - path := config.Path - module := config.Module - log.Printf("[TRACE] ConfigTransformer: Starting for path: %v", path) - - allResources := make([]*configs.Resource, 0, len(module.ManagedResources)+len(module.DataResources)) - for _, r := range module.ManagedResources { - allResources = append(allResources, r) - } - for _, r := range module.DataResources { - allResources = append(allResources, r) - } - - for _, r := range allResources { - relAddr := r.Addr() - - if t.ModeFilter && relAddr.Mode != t.Mode { - // Skip non-matching modes - continue - } - - // If any of the import targets can apply to this node's instances, - // filter them down to the applicable addresses. - var imports []*ImportTarget - configAddr := relAddr.InModule(path) - for _, i := range t.importTargets { - if target := i.Addr.ContainingResource().Config(); target.Equal(configAddr) { - imports = append(imports, i) - } - } - - abstract := &NodeAbstractResource{ - Addr: addrs.ConfigResource{ - Resource: relAddr, - Module: path, - }, - importTargets: imports, - } - - var node dag.Vertex = abstract - if f := t.Concrete; f != nil { - node = f(abstract) - } - - g.Add(node) - } - - return nil -} diff --git a/internal/terraform/transform_config_test.go b/internal/terraform/transform_config_test.go deleted file mode 100644 index ceed2bf35651..000000000000 --- a/internal/terraform/transform_config_test.go +++ /dev/null @@ -1,86 +0,0 @@ -package terraform - -import ( - "strings" - "testing" - - "github.com/hashicorp/terraform/internal/addrs" -) - -func TestConfigTransformer_nilModule(t *testing.T) { - g := Graph{Path: addrs.RootModuleInstance} - tf := &ConfigTransformer{} - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - - if len(g.Vertices()) > 0 { - t.Fatalf("graph is not empty: %s", g.String()) - } -} - -func TestConfigTransformer(t *testing.T) { - g := Graph{Path: addrs.RootModuleInstance} - tf := &ConfigTransformer{Config: testModule(t, "graph-basic")} - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(testConfigTransformerGraphBasicStr) - if actual != expected { - t.Fatalf("bad:\n\n%s", actual) - } -} - -func TestConfigTransformer_mode(t *testing.T) { - g := Graph{Path: addrs.RootModuleInstance} - tf := &ConfigTransformer{ - Config: testModule(t, "transform-config-mode-data"), - ModeFilter: true, - Mode: addrs.DataResourceMode, - } - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(` -data.aws_ami.foo -`) - if actual != expected { - t.Fatalf("bad:\n\n%s", actual) - } -} - -func TestConfigTransformer_nonUnique(t *testing.T) { - g := Graph{Path: addrs.RootModuleInstance} - g.Add(NewNodeAbstractResource( - addrs.RootModule.Resource( - addrs.ManagedResourceMode, "aws_instance", "web", - ), - )) - tf := &ConfigTransformer{Config: testModule(t, "graph-basic")} - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(` -aws_instance.web -aws_instance.web -aws_load_balancer.weblb -aws_security_group.firewall -openstack_floating_ip.random -`) - if actual != expected { - t.Fatalf("bad:\n\n%s", actual) - } -} - -const testConfigTransformerGraphBasicStr = ` -aws_instance.web -aws_load_balancer.weblb -aws_security_group.firewall -openstack_floating_ip.random -` diff --git a/internal/terraform/transform_destroy_cbd.go b/internal/terraform/transform_destroy_cbd.go deleted file mode 100644 index 19dadbe5ae1a..000000000000 --- a/internal/terraform/transform_destroy_cbd.go +++ /dev/null @@ -1,150 +0,0 @@ -package terraform - -import ( - "fmt" - "log" - - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/dag" - "github.com/hashicorp/terraform/internal/states" -) - -// GraphNodeDestroyerCBD must be implemented by nodes that might be -// create-before-destroy destroyers, or might plan a create-before-destroy -// action. -type GraphNodeDestroyerCBD interface { - // CreateBeforeDestroy returns true if this node represents a node - // that is doing a CBD. - CreateBeforeDestroy() bool - - // ModifyCreateBeforeDestroy is called when the CBD state of a node - // is changed dynamically. This can return an error if this isn't - // allowed. - ModifyCreateBeforeDestroy(bool) error -} - -// ForcedCBDTransformer detects when a particular CBD-able graph node has -// dependencies with another that has create_before_destroy set that require -// it to be forced on, and forces it on. -// -// This must be used in the plan graph builder to ensure that -// create_before_destroy settings are properly propagated before constructing -// the planned changes. This requires that the plannable resource nodes -// implement GraphNodeDestroyerCBD. -type ForcedCBDTransformer struct { -} - -func (t *ForcedCBDTransformer) Transform(g *Graph) error { - for _, v := range g.Vertices() { - dn, ok := v.(GraphNodeDestroyerCBD) - if !ok { - continue - } - - if !dn.CreateBeforeDestroy() { - // If there are no CBD decendent (dependent nodes), then we - // do nothing here. - if !t.hasCBDDescendent(g, v) { - log.Printf("[TRACE] ForcedCBDTransformer: %q (%T) has no CBD descendent, so skipping", dag.VertexName(v), v) - continue - } - - // If this isn't naturally a CBD node, this means that an descendent is - // and we need to auto-upgrade this node to CBD. We do this because - // a CBD node depending on non-CBD will result in cycles. To avoid this, - // we always attempt to upgrade it. - log.Printf("[TRACE] ForcedCBDTransformer: forcing create_before_destroy on for %q (%T)", dag.VertexName(v), v) - if err := dn.ModifyCreateBeforeDestroy(true); err != nil { - return fmt.Errorf( - "%s: must have create before destroy enabled because "+ - "a dependent resource has CBD enabled. However, when "+ - "attempting to automatically do this, an error occurred: %s", - dag.VertexName(v), err) - } - } else { - log.Printf("[TRACE] ForcedCBDTransformer: %q (%T) already has create_before_destroy set", dag.VertexName(v), v) - } - } - return nil -} - -// hasCBDDescendent returns true if any descendent (node that depends on this) -// has CBD set. -func (t *ForcedCBDTransformer) hasCBDDescendent(g *Graph, v dag.Vertex) bool { - s, _ := g.Descendents(v) - if s == nil { - return true - } - - for _, ov := range s { - dn, ok := ov.(GraphNodeDestroyerCBD) - if !ok { - continue - } - - if dn.CreateBeforeDestroy() { - // some descendent is CreateBeforeDestroy, so we need to follow suit - log.Printf("[TRACE] ForcedCBDTransformer: %q has CBD descendent %q", dag.VertexName(v), dag.VertexName(ov)) - return true - } - } - - return false -} - -// CBDEdgeTransformer modifies the edges of create-before-destroy ("CBD") nodes -// that went through the DestroyEdgeTransformer so that they will have the -// correct dependencies. There are two parts to this: -// -// 1. With CBD, the destroy edge is inverted: the destroy depends on -// the creation. -// -// 2. Destroy for A must depend on resources that depend on A. This is to -// allow the destroy to only happen once nodes that depend on A successfully -// update to A. Example: adding a web server updates the load balancer -// before deleting the old web server. -// -// This transformer requires that a previous transformer has already forced -// create_before_destroy on for nodes that are depended on by explicit CBD -// nodes. This is the logic in ForcedCBDTransformer, though in practice we -// will get here by recording the CBD-ness of each change in the plan during -// the plan walk and then forcing the nodes into the appropriate setting during -// DiffTransformer when building the apply graph. -type CBDEdgeTransformer struct { - // Module and State are only needed to look up dependencies in - // any way possible. Either can be nil if not availabile. - Config *configs.Config - State *states.State -} - -func (t *CBDEdgeTransformer) Transform(g *Graph) error { - // Go through and reverse any destroy edges - for _, v := range g.Vertices() { - dn, ok := v.(GraphNodeDestroyerCBD) - if !ok { - continue - } - if _, ok = v.(GraphNodeDestroyer); !ok { - continue - } - - if !dn.CreateBeforeDestroy() { - continue - } - - // Find the resource edges - for _, e := range g.EdgesTo(v) { - src := e.Source() - - // If source is a create node, invert the edge. - // This covers both the node's own creator, as well as reversing - // any dependants' edges. - if _, ok := src.(GraphNodeCreator); ok { - log.Printf("[TRACE] CBDEdgeTransformer: reversing edge %s -> %s", dag.VertexName(src), dag.VertexName(v)) - g.RemoveEdge(e) - g.Connect(dag.BasicEdge(v, src)) - } - } - } - return nil -} diff --git a/internal/terraform/transform_destroy_cbd_test.go b/internal/terraform/transform_destroy_cbd_test.go deleted file mode 100644 index 8f5712b57449..000000000000 --- a/internal/terraform/transform_destroy_cbd_test.go +++ /dev/null @@ -1,360 +0,0 @@ -package terraform - -import ( - "regexp" - "strings" - "testing" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states" -) - -func cbdTestGraph(t *testing.T, mod string, changes *plans.Changes, state *states.State) *Graph { - module := testModule(t, mod) - - applyBuilder := &ApplyGraphBuilder{ - Config: module, - Changes: changes, - Plugins: simpleMockPluginLibrary(), - State: state, - } - g, err := (&BasicGraphBuilder{ - Steps: cbdTestSteps(applyBuilder.Steps()), - Name: "ApplyGraphBuilder", - }).Build(addrs.RootModuleInstance) - if err != nil { - t.Fatalf("err: %s", err) - } - - return filterInstances(g) -} - -// override the apply graph builder to halt the process after CBD -func cbdTestSteps(steps []GraphTransformer) []GraphTransformer { - found := false - var i int - var t GraphTransformer - for i, t = range steps { - if _, ok := t.(*CBDEdgeTransformer); ok { - found = true - break - } - } - - if !found { - panic("CBDEdgeTransformer not found") - } - - // re-add the root node so we have a valid graph for a walk, then reduce - // the graph for less output - steps = append(steps[:i+1], &CloseRootModuleTransformer{}) - steps = append(steps, &TransitiveReductionTransformer{}) - - return steps -} - -// remove extra nodes for easier test comparisons -func filterInstances(g *Graph) *Graph { - for _, v := range g.Vertices() { - if _, ok := v.(GraphNodeResourceInstance); !ok { - g.Remove(v) - } - - } - return g -} - -func TestCBDEdgeTransformer(t *testing.T) { - changes := &plans.Changes{ - Resources: []*plans.ResourceInstanceChangeSrc{ - { - Addr: mustResourceInstanceAddr("test_object.A"), - ChangeSrc: plans.ChangeSrc{ - Action: plans.CreateThenDelete, - }, - }, - { - Addr: mustResourceInstanceAddr("test_object.B"), - ChangeSrc: plans.ChangeSrc{ - Action: plans.Update, - }, - }, - }, - } - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.A").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"A"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.B").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"B","test_list":["x"]}`), - Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.A")}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - g := cbdTestGraph(t, "transform-destroy-cbd-edge-basic", changes, state) - g = filterInstances(g) - - actual := strings.TrimSpace(g.String()) - expected := regexp.MustCompile(strings.TrimSpace(` -(?m)test_object.A -test_object.A \(destroy deposed \w+\) - test_object.B -test_object.B - test_object.A -`)) - - if !expected.MatchString(actual) { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestCBDEdgeTransformerMulti(t *testing.T) { - changes := &plans.Changes{ - Resources: []*plans.ResourceInstanceChangeSrc{ - { - Addr: mustResourceInstanceAddr("test_object.A"), - ChangeSrc: plans.ChangeSrc{ - Action: plans.CreateThenDelete, - }, - }, - { - Addr: mustResourceInstanceAddr("test_object.B"), - ChangeSrc: plans.ChangeSrc{ - Action: plans.CreateThenDelete, - }, - }, - { - Addr: mustResourceInstanceAddr("test_object.C"), - ChangeSrc: plans.ChangeSrc{ - Action: plans.Update, - }, - }, - }, - } - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.A").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"A"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.B").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"B"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.C").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"C","test_list":["x"]}`), - Dependencies: []addrs.ConfigResource{ - mustConfigResourceAddr("test_object.A"), - mustConfigResourceAddr("test_object.B"), - }, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - g := cbdTestGraph(t, "transform-destroy-cbd-edge-multi", changes, state) - g = filterInstances(g) - - actual := strings.TrimSpace(g.String()) - expected := regexp.MustCompile(strings.TrimSpace(` -(?m)test_object.A -test_object.A \(destroy deposed \w+\) - test_object.C -test_object.B -test_object.B \(destroy deposed \w+\) - test_object.C -test_object.C - test_object.A - test_object.B -`)) - - if !expected.MatchString(actual) { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestCBDEdgeTransformer_depNonCBDCount(t *testing.T) { - changes := &plans.Changes{ - Resources: []*plans.ResourceInstanceChangeSrc{ - { - Addr: mustResourceInstanceAddr("test_object.A"), - ChangeSrc: plans.ChangeSrc{ - Action: plans.CreateThenDelete, - }, - }, - { - Addr: mustResourceInstanceAddr("test_object.B[0]"), - ChangeSrc: plans.ChangeSrc{ - Action: plans.Update, - }, - }, - { - Addr: mustResourceInstanceAddr("test_object.B[1]"), - ChangeSrc: plans.ChangeSrc{ - Action: plans.Update, - }, - }, - }, - } - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.A").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"A"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.B[0]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"B","test_list":["x"]}`), - Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.A")}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.B[1]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"B","test_list":["x"]}`), - Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.A")}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - g := cbdTestGraph(t, "transform-cbd-destroy-edge-count", changes, state) - - actual := strings.TrimSpace(g.String()) - expected := regexp.MustCompile(strings.TrimSpace(` -(?m)test_object.A -test_object.A \(destroy deposed \w+\) - test_object.B\[0\] - test_object.B\[1\] -test_object.B\[0\] - test_object.A -test_object.B\[1\] - test_object.A`)) - - if !expected.MatchString(actual) { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestCBDEdgeTransformer_depNonCBDCountBoth(t *testing.T) { - changes := &plans.Changes{ - Resources: []*plans.ResourceInstanceChangeSrc{ - { - Addr: mustResourceInstanceAddr("test_object.A[0]"), - ChangeSrc: plans.ChangeSrc{ - Action: plans.CreateThenDelete, - }, - }, - { - Addr: mustResourceInstanceAddr("test_object.A[1]"), - ChangeSrc: plans.ChangeSrc{ - Action: plans.CreateThenDelete, - }, - }, - { - Addr: mustResourceInstanceAddr("test_object.B[0]"), - ChangeSrc: plans.ChangeSrc{ - Action: plans.Update, - }, - }, - { - Addr: mustResourceInstanceAddr("test_object.B[1]"), - ChangeSrc: plans.ChangeSrc{ - Action: plans.Update, - }, - }, - }, - } - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.A[0]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"A"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.A[1]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"A"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.B[0]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"B","test_list":["x"]}`), - Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.A")}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.B[1]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"B","test_list":["x"]}`), - Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.A")}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - g := cbdTestGraph(t, "transform-cbd-destroy-edge-both-count", changes, state) - - actual := strings.TrimSpace(g.String()) - expected := regexp.MustCompile(strings.TrimSpace(` -test_object.A\[0\] -test_object.A\[0\] \(destroy deposed \w+\) - test_object.B\[0\] - test_object.B\[1\] -test_object.A\[1\] -test_object.A\[1\] \(destroy deposed \w+\) - test_object.B\[0\] - test_object.B\[1\] -test_object.B\[0\] - test_object.A\[0\] - test_object.A\[1\] -test_object.B\[1\] - test_object.A\[0\] - test_object.A\[1\] -`)) - - if !expected.MatchString(actual) { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} diff --git a/internal/terraform/transform_destroy_edge.go b/internal/terraform/transform_destroy_edge.go deleted file mode 100644 index 3f87e7edf375..000000000000 --- a/internal/terraform/transform_destroy_edge.go +++ /dev/null @@ -1,374 +0,0 @@ -package terraform - -import ( - "log" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/dag" - "github.com/hashicorp/terraform/internal/plans" -) - -// GraphNodeDestroyer must be implemented by nodes that destroy resources. -type GraphNodeDestroyer interface { - dag.Vertex - - // DestroyAddr is the address of the resource that is being - // destroyed by this node. If this returns nil, then this node - // is not destroying anything. - DestroyAddr() *addrs.AbsResourceInstance -} - -// GraphNodeCreator must be implemented by nodes that create OR update resources. -type GraphNodeCreator interface { - // CreateAddr is the address of the resource being created or updated - CreateAddr() *addrs.AbsResourceInstance -} - -// DestroyEdgeTransformer is a GraphTransformer that creates the proper -// references for destroy resources. Destroy resources are more complex -// in that they must be depend on the destruction of resources that -// in turn depend on the CREATION of the node being destroy. -// -// That is complicated. Visually: -// -// B_d -> A_d -> A -> B -// -// Notice that A destroy depends on B destroy, while B create depends on -// A create. They're inverted. This must be done for example because often -// dependent resources will block parent resources from deleting. Concrete -// example: VPC with subnets, the VPC can't be deleted while there are -// still subnets. -type DestroyEdgeTransformer struct { - // FIXME: GraphNodeCreators are not always applying changes, and should not - // participate in the destroy graph if there are no operations which could - // interract with destroy nodes. We need Changes for now to detect the - // action type, but perhaps this should be indicated somehow by the - // DiffTransformer which was intended to be the only transformer operating - // from the change set. - Changes *plans.Changes - - // FIXME: Operation will not be needed here one we can better track - // inter-provider dependencies and remove the cycle checks in - // tryInterProviderDestroyEdge. - Operation walkOperation -} - -// tryInterProviderDestroyEdge checks if we're inserting a destroy edge -// across a provider boundary, and only adds the edge if it results in no cycles. -// -// FIXME: The cycles can arise in valid configurations when a provider depends -// on resources from another provider. In the future we may want to inspect -// the dependencies of the providers themselves, to avoid needing to use the -// blunt hammer of checking for cycles. -// -// A reduced example of this dependency problem looks something like: -/* - -createA <- createB - | \ / | - | providerB <- | - v \ v -destroyA -------------> destroyB - -*/ -// -// The edge from destroyA to destroyB would be skipped in this case, but there -// are still other combinations of changes which could connect the A and B -// groups around providerB in various ways. -// -// The most difficult problem here happens during a full destroy operation. -// That creates a special case where resources on which a provider depends must -// exist for evaluation before they are destroyed. This means that any provider -// dependencies must wait until all that provider's resources have first been -// destroyed. This is where these cross-provider edges are still required to -// ensure the correct order. -func (t *DestroyEdgeTransformer) tryInterProviderDestroyEdge(g *Graph, from, to dag.Vertex) { - e := dag.BasicEdge(from, to) - g.Connect(e) - - // If this is a complete destroy operation, then there are no create/update - // nodes to worry about and we can accept the edge without deeper inspection. - if t.Operation == walkDestroy { - return - } - - // getComparableProvider inspects the node to try and get the most precise - // description of the provider being used to help determine if 2 nodes are - // from the same provider instance. - getComparableProvider := func(pc GraphNodeProviderConsumer) string { - ps := pc.Provider().String() - - // we don't care about `exact` here, since we're only looking for any - // clue that the providers may differ. - p, _ := pc.ProvidedBy() - switch p := p.(type) { - case addrs.AbsProviderConfig: - ps = p.String() - case addrs.LocalProviderConfig: - ps = p.String() - } - - return ps - } - - pc, ok := from.(GraphNodeProviderConsumer) - if !ok { - return - } - fromProvider := getComparableProvider(pc) - - pc, ok = to.(GraphNodeProviderConsumer) - if !ok { - return - } - toProvider := getComparableProvider(pc) - - // Check for cycles, and back out the edge if there are any. - // The cycles we are looking for only appears between providers, so don't - // waste time checking for cycles if both nodes use the same provider. - if fromProvider != toProvider && len(g.Cycles()) > 0 { - log.Printf("[DEBUG] DestroyEdgeTransformer: skipping inter-provider edge %s->%s which creates a cycle", - dag.VertexName(from), dag.VertexName(to)) - g.RemoveEdge(e) - } -} - -func (t *DestroyEdgeTransformer) Transform(g *Graph) error { - // Build a map of what is being destroyed (by address string) to - // the list of destroyers. - destroyers := make(map[string][]GraphNodeDestroyer) - - // Record the creators, which will need to depend on the destroyers if they - // are only being updated. - creators := make(map[string][]GraphNodeCreator) - - // destroyersByResource records each destroyer by the ConfigResource - // address. We use this because dependencies are only referenced as - // resources and have no index or module instance information, but we will - // want to connect all the individual instances for correct ordering. - destroyersByResource := make(map[string][]GraphNodeDestroyer) - for _, v := range g.Vertices() { - switch n := v.(type) { - case GraphNodeDestroyer: - addrP := n.DestroyAddr() - if addrP == nil { - log.Printf("[WARN] DestroyEdgeTransformer: %q (%T) has no destroy address", dag.VertexName(n), v) - continue - } - addr := *addrP - - key := addr.String() - log.Printf("[TRACE] DestroyEdgeTransformer: %q (%T) destroys %s", dag.VertexName(n), v, key) - destroyers[key] = append(destroyers[key], n) - - resAddr := addr.ContainingResource().Config().String() - destroyersByResource[resAddr] = append(destroyersByResource[resAddr], n) - case GraphNodeCreator: - addr := n.CreateAddr() - cfgAddr := addr.ContainingResource().Config().String() - - if t.Changes == nil { - // unit tests may not have changes - creators[cfgAddr] = append(creators[cfgAddr], n) - break - } - - // NoOp changes should not participate in the destroy dependencies. - rc := t.Changes.ResourceInstance(*addr) - if rc != nil && rc.Action != plans.NoOp { - creators[cfgAddr] = append(creators[cfgAddr], n) - } - } - } - - // If we aren't destroying anything, there will be no edges to make - // so just exit early and avoid future work. - if len(destroyers) == 0 { - return nil - } - - // Go through and connect creators to destroyers. Going along with - // our example, this makes: A_d => A - for _, v := range g.Vertices() { - cn, ok := v.(GraphNodeCreator) - if !ok { - continue - } - - addr := cn.CreateAddr() - if addr == nil { - continue - } - - for _, d := range destroyers[addr.String()] { - // For illustrating our example - a_d := d.(dag.Vertex) - a := v - - log.Printf( - "[TRACE] DestroyEdgeTransformer: connecting creator %q with destroyer %q", - dag.VertexName(a), dag.VertexName(a_d)) - - g.Connect(dag.BasicEdge(a, a_d)) - } - } - - // connect creators to any destroyers on which they may depend - for _, cs := range creators { - for _, c := range cs { - ri, ok := c.(GraphNodeResourceInstance) - if !ok { - continue - } - - for _, resAddr := range ri.StateDependencies() { - for _, desDep := range destroyersByResource[resAddr.String()] { - if !graphNodesAreResourceInstancesInDifferentInstancesOfSameModule(c, desDep) { - log.Printf("[TRACE] DestroyEdgeTransformer: %s has stored dependency of %s\n", dag.VertexName(c), dag.VertexName(desDep)) - g.Connect(dag.BasicEdge(c, desDep)) - } else { - log.Printf("[TRACE] DestroyEdgeTransformer: skipping %s => %s inter-module-instance dependency\n", dag.VertexName(c), dag.VertexName(desDep)) - } - } - } - } - } - - // Connect destroy dependencies as stored in the state - for _, ds := range destroyers { - for _, des := range ds { - ri, ok := des.(GraphNodeResourceInstance) - if !ok { - continue - } - - for _, resAddr := range ri.StateDependencies() { - for _, desDep := range destroyersByResource[resAddr.String()] { - if !graphNodesAreResourceInstancesInDifferentInstancesOfSameModule(desDep, des) { - log.Printf("[TRACE] DestroyEdgeTransformer: %s has stored dependency of %s\n", dag.VertexName(desDep), dag.VertexName(des)) - t.tryInterProviderDestroyEdge(g, desDep, des) - } else { - log.Printf("[TRACE] DestroyEdgeTransformer: skipping %s => %s inter-module-instance dependency\n", dag.VertexName(desDep), dag.VertexName(des)) - } - } - - // We can have some create or update nodes which were - // dependents of the destroy node. If they have no destroyer - // themselves, make the connection directly from the creator. - for _, createDep := range creators[resAddr.String()] { - if !graphNodesAreResourceInstancesInDifferentInstancesOfSameModule(createDep, des) { - log.Printf("[DEBUG] DestroyEdgeTransformer2: %s has stored dependency of %s\n", dag.VertexName(createDep), dag.VertexName(des)) - t.tryInterProviderDestroyEdge(g, createDep, des) - } else { - log.Printf("[TRACE] DestroyEdgeTransformer2: skipping %s => %s inter-module-instance dependency\n", dag.VertexName(createDep), dag.VertexName(des)) - } - } - } - } - } - - return nil -} - -// Remove any nodes that aren't needed when destroying modules. -// Variables, outputs, locals, and expanders may not be able to evaluate -// correctly, so we can remove these if nothing depends on them. The module -// closers also need to disable their use of expansion if the module itself is -// no longer present. -type pruneUnusedNodesTransformer struct { - // The plan graph builder will skip this transformer except during a full - // destroy. Planing normally involves all nodes, but during a destroy plan - // we may need to prune things which are in the configuration but do not - // exist in state to evaluate. - skip bool -} - -func (t *pruneUnusedNodesTransformer) Transform(g *Graph) error { - if t.skip { - return nil - } - - // We need a reverse depth first walk of modules, processing them in order - // from the leaf modules to the root. This allows us to remove unneeded - // dependencies from child modules, freeing up nodes in the parent module - // to also be removed. - - nodes := g.Vertices() - - for removed := true; removed; { - removed = false - - for i := 0; i < len(nodes); i++ { - // run this in a closure, so we can return early rather than - // dealing with complex looping and labels - func() { - n := nodes[i] - switch n := n.(type) { - case graphNodeTemporaryValue: - // root module outputs indicate they are not temporary by - // returning false here. - if !n.temporaryValue() { - return - } - - // temporary values, which consist of variables, locals, - // and outputs, must be kept if anything refers to them. - for _, v := range g.UpEdges(n) { - // keep any value which is connected through a - // reference - if _, ok := v.(GraphNodeReferencer); ok { - return - } - } - - case graphNodeExpandsInstances: - // Any nodes that expand instances are kept when their - // instances may need to be evaluated. - for _, v := range g.UpEdges(n) { - switch v.(type) { - case graphNodeExpandsInstances: - // Root module output values (which the following - // condition matches) are exempt because we know - // there is only ever exactly one instance of the - // root module, and so it's not actually important - // to expand it and so this lets us do a bit more - // pruning than we'd be able to do otherwise. - if tmp, ok := v.(graphNodeTemporaryValue); ok && !tmp.temporaryValue() { - continue - } - - // expanders can always depend on module expansion - // themselves - return - case GraphNodeResourceInstance: - // resource instances always depend on their - // resource node, which is an expander - return - } - } - - case GraphNodeProvider: - // Providers that may have been required by expansion nodes - // that we no longer need can also be removed. - if g.UpEdges(n).Len() > 0 { - return - } - - default: - return - } - - log.Printf("[DEBUG] pruneUnusedNodes: %s is no longer needed, removing", dag.VertexName(n)) - g.Remove(n) - removed = true - - // remove the node from our iteration as well - last := len(nodes) - 1 - nodes[i], nodes[last] = nodes[last], nodes[i] - nodes = nodes[:last] - }() - } - } - - return nil -} diff --git a/internal/terraform/transform_destroy_edge_test.go b/internal/terraform/transform_destroy_edge_test.go deleted file mode 100644 index c82d07e38544..000000000000 --- a/internal/terraform/transform_destroy_edge_test.go +++ /dev/null @@ -1,595 +0,0 @@ -package terraform - -import ( - "fmt" - "strings" - "testing" - - "github.com/davecgh/go-spew/spew" - "github.com/zclconf/go-cty/cty" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/dag" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states" -) - -func TestDestroyEdgeTransformer_basic(t *testing.T) { - g := Graph{Path: addrs.RootModuleInstance} - g.Add(testDestroyNode("test_object.A")) - g.Add(testDestroyNode("test_object.B")) - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.A").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"A"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.B").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"B","test_string":"x"}`), - Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.A")}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - if err := (&AttachStateTransformer{State: state}).Transform(&g); err != nil { - t.Fatal(err) - } - - tf := &DestroyEdgeTransformer{} - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(testTransformDestroyEdgeBasicStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestDestroyEdgeTransformer_multi(t *testing.T) { - g := Graph{Path: addrs.RootModuleInstance} - g.Add(testDestroyNode("test_object.A")) - g.Add(testDestroyNode("test_object.B")) - g.Add(testDestroyNode("test_object.C")) - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.A").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"A"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.B").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"B","test_string":"x"}`), - Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.A")}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.C").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"C","test_string":"x"}`), - Dependencies: []addrs.ConfigResource{ - mustConfigResourceAddr("test_object.A"), - mustConfigResourceAddr("test_object.B"), - }, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - if err := (&AttachStateTransformer{State: state}).Transform(&g); err != nil { - t.Fatal(err) - } - - tf := &DestroyEdgeTransformer{} - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(testTransformDestroyEdgeMultiStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestDestroyEdgeTransformer_selfRef(t *testing.T) { - g := Graph{Path: addrs.RootModuleInstance} - g.Add(testDestroyNode("test_object.A")) - tf := &DestroyEdgeTransformer{} - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(testTransformDestroyEdgeSelfRefStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestDestroyEdgeTransformer_module(t *testing.T) { - g := Graph{Path: addrs.RootModuleInstance} - g.Add(testDestroyNode("module.child.test_object.b")) - g.Add(testDestroyNode("test_object.a")) - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey)) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.a").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"a"}`), - Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("module.child.test_object.b")}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - child.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.b").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"b","test_string":"x"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - if err := (&AttachStateTransformer{State: state}).Transform(&g); err != nil { - t.Fatal(err) - } - - tf := &DestroyEdgeTransformer{} - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(testTransformDestroyEdgeModuleStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestDestroyEdgeTransformer_moduleOnly(t *testing.T) { - g := Graph{Path: addrs.RootModuleInstance} - - state := states.NewState() - for moduleIdx := 0; moduleIdx < 2; moduleIdx++ { - g.Add(testDestroyNode(fmt.Sprintf("module.child[%d].test_object.a", moduleIdx))) - g.Add(testDestroyNode(fmt.Sprintf("module.child[%d].test_object.b", moduleIdx))) - g.Add(testDestroyNode(fmt.Sprintf("module.child[%d].test_object.c", moduleIdx))) - - child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.IntKey(moduleIdx))) - child.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.a").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"a"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - child.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.b").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"b","test_string":"x"}`), - Dependencies: []addrs.ConfigResource{ - mustConfigResourceAddr("module.child.test_object.a"), - }, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - child.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.c").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"c","test_string":"x"}`), - Dependencies: []addrs.ConfigResource{ - mustConfigResourceAddr("module.child.test_object.a"), - mustConfigResourceAddr("module.child.test_object.b"), - }, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - } - - if err := (&AttachStateTransformer{State: state}).Transform(&g); err != nil { - t.Fatal(err) - } - - tf := &DestroyEdgeTransformer{} - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - - // The analyses done in the destroy edge transformer are between - // not-yet-expanded objects, which is conservative and so it will generate - // edges that aren't strictly necessary. As a special case we filter out - // any edges that are between resources instances that are in different - // instances of the same module, because those edges are never needed - // (one instance of a module cannot depend on another instance of the - // same module) and including them can, in complex cases, cause cycles due - // to unnecessary interactions between destroyed and created module - // instances in the same plan. - // - // Therefore below we expect to see the dependencies within each instance - // of module.child reflected, but we should not see any dependencies - // _between_ instances of module.child. - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(` -module.child[0].test_object.a (destroy) - module.child[0].test_object.b (destroy) - module.child[0].test_object.c (destroy) -module.child[0].test_object.b (destroy) - module.child[0].test_object.c (destroy) -module.child[0].test_object.c (destroy) -module.child[1].test_object.a (destroy) - module.child[1].test_object.b (destroy) - module.child[1].test_object.c (destroy) -module.child[1].test_object.b (destroy) - module.child[1].test_object.c (destroy) -module.child[1].test_object.c (destroy) -`) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestDestroyEdgeTransformer_destroyThenUpdate(t *testing.T) { - g := Graph{Path: addrs.RootModuleInstance} - g.Add(testUpdateNode("test_object.A")) - g.Add(testDestroyNode("test_object.B")) - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.A").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"A","test_string":"old"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.B").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"B","test_string":"x"}`), - Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.A")}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - if err := (&AttachStateTransformer{State: state}).Transform(&g); err != nil { - t.Fatal(err) - } - - tf := &DestroyEdgeTransformer{} - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - - expected := strings.TrimSpace(` -test_object.A - test_object.B (destroy) -test_object.B (destroy) -`) - actual := strings.TrimSpace(g.String()) - - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestPruneUnusedNodesTransformer_rootModuleOutputValues(t *testing.T) { - // This is a kinda-weird test case covering the very narrow situation - // where a root module output value depends on a resource, where we - // need to make sure that the output value doesn't block pruning of - // the resource from the graph. This special case exists because although - // root module objects are "expanders", they in practice always expand - // to exactly one instance and so don't have the usual requirement of - // needing to stick around in order to support downstream expanders - // when there are e.g. nested expanding modules. - - // In order to keep this test focused on the pruneUnusedNodesTransformer - // as much as possible we're using a minimal graph construction here which - // is just enough to get the nodes we need, but this does mean that this - // test might be invalidated by future changes to the apply graph builder, - // and so if something seems off here it might help to compare the - // following with the real apply graph transformer and verify whether - // this smaller construction is still realistic enough to be a valid test. - // It might be valid to change or remove this test to "make it work", as - // long as you verify that there is still _something_ upholding the - // invariant that a root module output value should not block a resource - // node from being pruned from the graph. - - concreteResource := func(a *NodeAbstractResource) dag.Vertex { - return &nodeExpandApplyableResource{ - NodeAbstractResource: a, - } - } - - concreteResourceInstance := func(a *NodeAbstractResourceInstance) dag.Vertex { - return &NodeApplyableResourceInstance{ - NodeAbstractResourceInstance: a, - } - } - - resourceInstAddr := mustResourceInstanceAddr("test.a") - providerCfgAddr := addrs.AbsProviderConfig{ - Module: addrs.RootModule, - Provider: addrs.MustParseProviderSourceString("foo/test"), - } - emptyObjDynamicVal, err := plans.NewDynamicValue(cty.EmptyObjectVal, cty.EmptyObject) - if err != nil { - t.Fatal(err) - } - nullObjDynamicVal, err := plans.NewDynamicValue(cty.NullVal(cty.EmptyObject), cty.EmptyObject) - if err != nil { - t.Fatal(err) - } - - config := testModuleInline(t, map[string]string{ - "main.tf": ` - resource "test" "a" { - } - - output "test" { - value = test.a.foo - } - `, - }) - state := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent( - resourceInstAddr, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{}`), - }, - providerCfgAddr, - ) - }) - changes := plans.NewChanges() - changes.SyncWrapper().AppendResourceInstanceChange(&plans.ResourceInstanceChangeSrc{ - Addr: resourceInstAddr, - PrevRunAddr: resourceInstAddr, - ProviderAddr: providerCfgAddr, - ChangeSrc: plans.ChangeSrc{ - Action: plans.Delete, - Before: emptyObjDynamicVal, - After: nullObjDynamicVal, - }, - }) - - builder := &BasicGraphBuilder{ - Steps: []GraphTransformer{ - &ConfigTransformer{ - Concrete: concreteResource, - Config: config, - }, - &OutputTransformer{ - Config: config, - }, - &DiffTransformer{ - Concrete: concreteResourceInstance, - State: state, - Changes: changes, - }, - &ReferenceTransformer{}, - &AttachDependenciesTransformer{}, - &pruneUnusedNodesTransformer{}, - &CloseRootModuleTransformer{}, - }, - } - graph, diags := builder.Build(addrs.RootModuleInstance) - assertNoDiagnostics(t, diags) - - // At this point, thanks to pruneUnusedNodesTransformer, we should still - // have the node for the output value, but the "test.a (expand)" node - // should've been pruned in recognition of the fact that we're performing - // a destroy and therefore we only need the "test.a (destroy)" node. - - nodesByName := make(map[string]dag.Vertex) - nodesByResourceExpand := make(map[string]dag.Vertex) - for _, n := range graph.Vertices() { - name := dag.VertexName(n) - if _, exists := nodesByName[name]; exists { - t.Fatalf("multiple nodes have name %q", name) - } - nodesByName[name] = n - - if exp, ok := n.(*nodeExpandApplyableResource); ok { - addr := exp.Addr - if _, exists := nodesByResourceExpand[addr.String()]; exists { - t.Fatalf("multiple nodes are expanders for %s", addr) - } - nodesByResourceExpand[addr.String()] = exp - } - } - - // NOTE: The following is sensitive to the current name string formats we - // use for these particular node types. These names are not contractual - // so if this breaks in future it is fine to update these names to the new - // names as long as you verify first that the new names correspond to - // the same meaning as what we're assuming below. - if _, exists := nodesByName["test.a (destroy)"]; !exists { - t.Errorf("missing destroy node for resource instance test.a") - } - if _, exists := nodesByName["output.test (expand)"]; !exists { - t.Errorf("missing expand for output value 'test'") - } - - // We _must not_ have any node that expands a resource. - if len(nodesByResourceExpand) != 0 { - t.Errorf("resource expand nodes remain the graph after transform; should've been pruned\n%s", spew.Sdump(nodesByResourceExpand)) - } -} - -// NoOp changes should not be participating in the destroy sequence -func TestDestroyEdgeTransformer_noOp(t *testing.T) { - g := Graph{Path: addrs.RootModuleInstance} - g.Add(testDestroyNode("test_object.A")) - g.Add(testUpdateNode("test_object.B")) - g.Add(testDestroyNode("test_object.C")) - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.A").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"A"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.B").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"B","test_string":"x"}`), - Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.A")}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.C").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"C","test_string":"x"}`), - Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.A"), - mustConfigResourceAddr("test_object.B")}, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - if err := (&AttachStateTransformer{State: state}).Transform(&g); err != nil { - t.Fatal(err) - } - - tf := &DestroyEdgeTransformer{ - // We only need a minimal object to indicate GraphNodeCreator change is - // a NoOp here. - Changes: &plans.Changes{ - Resources: []*plans.ResourceInstanceChangeSrc{ - { - Addr: mustResourceInstanceAddr("test_object.B"), - ChangeSrc: plans.ChangeSrc{Action: plans.NoOp}, - }, - }, - }, - } - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - - expected := strings.TrimSpace(` -test_object.A (destroy) - test_object.C (destroy) -test_object.B -test_object.C (destroy)`) - - actual := strings.TrimSpace(g.String()) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestDestroyEdgeTransformer_dataDependsOn(t *testing.T) { - g := Graph{Path: addrs.RootModuleInstance} - - addrA := mustResourceInstanceAddr("test_object.A") - instA := NewNodeAbstractResourceInstance(addrA) - a := &NodeDestroyResourceInstance{NodeAbstractResourceInstance: instA} - g.Add(a) - - // B here represents a data sources, which is effectively an update during - // apply, but won't have dependencies stored in the state. - addrB := mustResourceInstanceAddr("test_object.B") - instB := NewNodeAbstractResourceInstance(addrB) - instB.Dependencies = append(instB.Dependencies, addrA.ConfigResource()) - b := &NodeApplyableResourceInstance{NodeAbstractResourceInstance: instB} - - g.Add(b) - - state := states.NewState() - root := state.EnsureModule(addrs.RootModuleInstance) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_object.A").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"A"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - - if err := (&AttachStateTransformer{State: state}).Transform(&g); err != nil { - t.Fatal(err) - } - - tf := &DestroyEdgeTransformer{} - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(` -test_object.A (destroy) -test_object.B - test_object.A (destroy) -`) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func testDestroyNode(addrString string) GraphNodeDestroyer { - instAddr := mustResourceInstanceAddr(addrString) - inst := NewNodeAbstractResourceInstance(instAddr) - return &NodeDestroyResourceInstance{NodeAbstractResourceInstance: inst} -} - -func testUpdateNode(addrString string) GraphNodeCreator { - instAddr := mustResourceInstanceAddr(addrString) - inst := NewNodeAbstractResourceInstance(instAddr) - return &NodeApplyableResourceInstance{NodeAbstractResourceInstance: inst} -} - -const testTransformDestroyEdgeBasicStr = ` -test_object.A (destroy) - test_object.B (destroy) -test_object.B (destroy) -` - -const testTransformDestroyEdgeMultiStr = ` -test_object.A (destroy) - test_object.B (destroy) - test_object.C (destroy) -test_object.B (destroy) - test_object.C (destroy) -test_object.C (destroy) -` - -const testTransformDestroyEdgeSelfRefStr = ` -test_object.A (destroy) -` - -const testTransformDestroyEdgeModuleStr = ` -module.child.test_object.b (destroy) - test_object.a (destroy) -test_object.a (destroy) -` diff --git a/internal/terraform/transform_diff.go b/internal/terraform/transform_diff.go deleted file mode 100644 index 3bce1131f5a5..000000000000 --- a/internal/terraform/transform_diff.go +++ /dev/null @@ -1,214 +0,0 @@ -package terraform - -import ( - "fmt" - "log" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/dag" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -// DiffTransformer is a GraphTransformer that adds graph nodes representing -// each of the resource changes described in the given Changes object. -type DiffTransformer struct { - Concrete ConcreteResourceInstanceNodeFunc - State *states.State - Changes *plans.Changes - Config *configs.Config -} - -// return true if the given resource instance has either Preconditions or -// Postconditions defined in the configuration. -func (t *DiffTransformer) hasConfigConditions(addr addrs.AbsResourceInstance) bool { - // unit tests may have no config - if t.Config == nil { - return false - } - - cfg := t.Config.DescendentForInstance(addr.Module) - if cfg == nil { - return false - } - - res := cfg.Module.ResourceByAddr(addr.ConfigResource().Resource) - if res == nil { - return false - } - - return len(res.Preconditions) > 0 || len(res.Postconditions) > 0 -} - -func (t *DiffTransformer) Transform(g *Graph) error { - if t.Changes == nil || len(t.Changes.Resources) == 0 { - // Nothing to do! - return nil - } - - // Go through all the modules in the diff. - log.Printf("[TRACE] DiffTransformer starting") - - var diags tfdiags.Diagnostics - state := t.State - changes := t.Changes - - // DiffTransformer creates resource _instance_ nodes. If there are any - // whole-resource nodes already in the graph, we must ensure that they - // get evaluated before any of the corresponding instances by creating - // dependency edges, so we'll do some prep work here to ensure we'll only - // create connections to nodes that existed before we started here. - resourceNodes := map[string][]GraphNodeConfigResource{} - for _, node := range g.Vertices() { - rn, ok := node.(GraphNodeConfigResource) - if !ok { - continue - } - // We ignore any instances that _also_ implement - // GraphNodeResourceInstance, since in the unlikely event that they - // do exist we'd probably end up creating cycles by connecting them. - if _, ok := node.(GraphNodeResourceInstance); ok { - continue - } - - addr := rn.ResourceAddr().String() - resourceNodes[addr] = append(resourceNodes[addr], rn) - } - - for _, rc := range changes.Resources { - addr := rc.Addr - dk := rc.DeposedKey - - log.Printf("[TRACE] DiffTransformer: found %s change for %s %s", rc.Action, addr, dk) - - // Depending on the action we'll need some different combinations of - // nodes, because destroying uses a special node type separate from - // other actions. - var update, delete, createBeforeDestroy bool - switch rc.Action { - case plans.NoOp: - // For a no-op change we don't take any action but we still - // run any condition checks associated with the object, to - // make sure that they still hold when considering the - // results of other changes. - update = t.hasConfigConditions(addr) - case plans.Delete: - delete = true - case plans.DeleteThenCreate, plans.CreateThenDelete: - update = true - delete = true - createBeforeDestroy = (rc.Action == plans.CreateThenDelete) - default: - update = true - } - - // A deposed instance may only have a change of Delete or NoOp. A NoOp - // can happen if the provider shows it no longer exists during the most - // recent ReadResource operation. - if dk != states.NotDeposed && !(rc.Action == plans.Delete || rc.Action == plans.NoOp) { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Invalid planned change for deposed object", - fmt.Sprintf("The plan contains a non-delete change for %s deposed object %s. The only valid action for a deposed object is to destroy it, so this is a bug in Terraform.", addr, dk), - )) - continue - } - - // If we're going to do a create_before_destroy Replace operation then - // we need to allocate a DeposedKey to use to retain the - // not-yet-destroyed prior object, so that the delete node can destroy - // _that_ rather than the newly-created node, which will be current - // by the time the delete node is visited. - if update && delete && createBeforeDestroy { - // In this case, variable dk will be the _pre-assigned_ DeposedKey - // that must be used if the update graph node deposes the current - // instance, which will then align with the same key we pass - // into the destroy node to ensure we destroy exactly the deposed - // object we expect. - if state != nil { - ris := state.ResourceInstance(addr) - if ris == nil { - // Should never happen, since we don't plan to replace an - // instance that doesn't exist yet. - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Invalid planned change", - fmt.Sprintf("The plan contains a replace change for %s, which doesn't exist yet. This is a bug in Terraform.", addr), - )) - continue - } - - // Allocating a deposed key separately from using it can be racy - // in general, but we assume here that nothing except the apply - // node we instantiate below will actually make new deposed objects - // in practice, and so the set of already-used keys will not change - // between now and then. - dk = ris.FindUnusedDeposedKey() - } else { - // If we have no state at all yet then we can use _any_ - // DeposedKey. - dk = states.NewDeposedKey() - } - } - - if update { - // All actions except destroying the node type chosen by t.Concrete - abstract := NewNodeAbstractResourceInstance(addr) - var node dag.Vertex = abstract - if f := t.Concrete; f != nil { - node = f(abstract) - } - - if createBeforeDestroy { - // We'll attach our pre-allocated DeposedKey to the node if - // it supports that. NodeApplyableResourceInstance is the - // specific concrete node type we are looking for here really, - // since that's the only node type that might depose objects. - if dn, ok := node.(GraphNodeDeposer); ok { - dn.SetPreallocatedDeposedKey(dk) - } - log.Printf("[TRACE] DiffTransformer: %s will be represented by %s, deposing prior object to %s", addr, dag.VertexName(node), dk) - } else { - log.Printf("[TRACE] DiffTransformer: %s will be represented by %s", addr, dag.VertexName(node)) - } - - g.Add(node) - rsrcAddr := addr.ContainingResource().String() - for _, rsrcNode := range resourceNodes[rsrcAddr] { - g.Connect(dag.BasicEdge(node, rsrcNode)) - } - } - - if delete { - // Destroying always uses a destroy-specific node type, though - // which one depends on whether we're destroying a current object - // or a deposed object. - var node GraphNodeResourceInstance - abstract := NewNodeAbstractResourceInstance(addr) - if dk == states.NotDeposed { - node = &NodeDestroyResourceInstance{ - NodeAbstractResourceInstance: abstract, - DeposedKey: dk, - } - } else { - node = &NodeDestroyDeposedResourceInstanceObject{ - NodeAbstractResourceInstance: abstract, - DeposedKey: dk, - } - } - if dk == states.NotDeposed { - log.Printf("[TRACE] DiffTransformer: %s will be represented for destruction by %s", addr, dag.VertexName(node)) - } else { - log.Printf("[TRACE] DiffTransformer: %s deposed object %s will be represented for destruction by %s", addr, dk, dag.VertexName(node)) - } - g.Add(node) - } - - } - - log.Printf("[TRACE] DiffTransformer complete") - - return diags.Err() -} diff --git a/internal/terraform/transform_diff_test.go b/internal/terraform/transform_diff_test.go deleted file mode 100644 index fa1feae34d61..000000000000 --- a/internal/terraform/transform_diff_test.go +++ /dev/null @@ -1,167 +0,0 @@ -package terraform - -import ( - "strings" - "testing" - - "github.com/zclconf/go-cty/cty" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/plans" -) - -func TestDiffTransformer_nilDiff(t *testing.T) { - g := Graph{Path: addrs.RootModuleInstance} - tf := &DiffTransformer{} - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - - if len(g.Vertices()) > 0 { - t.Fatal("graph should be empty") - } -} - -func TestDiffTransformer(t *testing.T) { - g := Graph{Path: addrs.RootModuleInstance} - - beforeVal, err := plans.NewDynamicValue(cty.StringVal(""), cty.String) - if err != nil { - t.Fatal(err) - } - afterVal, err := plans.NewDynamicValue(cty.StringVal(""), cty.String) - if err != nil { - t.Fatal(err) - } - - tf := &DiffTransformer{ - Changes: &plans.Changes{ - Resources: []*plans.ResourceInstanceChangeSrc{ - { - Addr: addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "foo", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - ProviderAddr: addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("aws"), - Module: addrs.RootModule, - }, - ChangeSrc: plans.ChangeSrc{ - Action: plans.Update, - Before: beforeVal, - After: afterVal, - }, - }, - }, - }, - } - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(testTransformDiffBasicStr) - if actual != expected { - t.Fatalf("bad:\n\n%s", actual) - } -} - -func TestDiffTransformer_noOpChange(t *testing.T) { - // "No-op" changes are how we record explicitly in a plan that we did - // indeed visit a particular resource instance during the planning phase - // and concluded that no changes were needed, as opposed to the resource - // instance not existing at all or having been excluded from planning - // entirely. - // - // We must include nodes for resource instances with no-op changes in the - // apply graph, even though they won't take any external actions, because - // there are some secondary effects such as precondition/postcondition - // checks that can refer to objects elsewhere and so might have their - // results changed even if the resource instance they are attached to - // didn't actually change directly itself. - - // aws_instance.foo has a precondition, so should be included in the final - // graph. aws_instance.bar has no conditions, so there is nothing to - // execute during apply and it should not be included in the graph. - m := testModuleInline(t, map[string]string{ - "main.tf": ` -resource "aws_instance" "bar" { -} - -resource "aws_instance" "foo" { - test_string = "ok" - - lifecycle { - precondition { - condition = self.test_string != "" - error_message = "resource error" - } - } -} -`}) - - g := Graph{Path: addrs.RootModuleInstance} - - beforeVal, err := plans.NewDynamicValue(cty.StringVal(""), cty.String) - if err != nil { - t.Fatal(err) - } - - tf := &DiffTransformer{ - Config: m, - Changes: &plans.Changes{ - Resources: []*plans.ResourceInstanceChangeSrc{ - { - Addr: addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "foo", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - ProviderAddr: addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("aws"), - Module: addrs.RootModule, - }, - ChangeSrc: plans.ChangeSrc{ - // A "no-op" change has the no-op action and has the - // same object as both Before and After. - Action: plans.NoOp, - Before: beforeVal, - After: beforeVal, - }, - }, - { - Addr: addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "bar", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - ProviderAddr: addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("aws"), - Module: addrs.RootModule, - }, - ChangeSrc: plans.ChangeSrc{ - // A "no-op" change has the no-op action and has the - // same object as both Before and After. - Action: plans.NoOp, - Before: beforeVal, - After: beforeVal, - }, - }, - }, - }, - } - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(testTransformDiffBasicStr) - if actual != expected { - t.Fatalf("bad:\n\n%s", actual) - } -} - -const testTransformDiffBasicStr = ` -aws_instance.foo -` diff --git a/internal/terraform/transform_expand.go b/internal/terraform/transform_expand.go deleted file mode 100644 index 6d9b92aeeedc..000000000000 --- a/internal/terraform/transform_expand.go +++ /dev/null @@ -1,17 +0,0 @@ -package terraform - -// GraphNodeDynamicExpandable is an interface that nodes can implement -// to signal that they can be expanded at eval-time (hence dynamic). -// These nodes are given the eval context and are expected to return -// a new subgraph. -type GraphNodeDynamicExpandable interface { - // DynamicExpand returns a new graph which will be treated as the dynamic - // subgraph of the receiving node. - // - // The second return value is of type error for historical reasons; - // it's valid (and most ideal) for DynamicExpand to return the result - // of calling ErrWithWarnings on a tfdiags.Diagnostics value instead, - // in which case the caller will unwrap it and gather the individual - // diagnostics. - DynamicExpand(EvalContext) (*Graph, error) -} diff --git a/internal/terraform/transform_import_state_test.go b/internal/terraform/transform_import_state_test.go deleted file mode 100644 index 919f09d84b8a..000000000000 --- a/internal/terraform/transform_import_state_test.go +++ /dev/null @@ -1,167 +0,0 @@ -package terraform - -import ( - "strings" - "testing" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" - "github.com/zclconf/go-cty/cty" -) - -func TestGraphNodeImportStateExecute(t *testing.T) { - state := states.NewState() - provider := testProvider("aws") - provider.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ - ImportedResources: []providers.ImportedResource{ - { - TypeName: "aws_instance", - State: cty.ObjectVal(map[string]cty.Value{ - "id": cty.StringVal("bar"), - }), - }, - }, - } - provider.ConfigureProvider(providers.ConfigureProviderRequest{}) - - ctx := &MockEvalContext{ - StateState: state.SyncWrapper(), - ProviderProvider: provider, - } - - // Import a new aws_instance.foo, this time with ID=bar. The original - // aws_instance.foo object should be removed from state and replaced with - // the new. - node := graphNodeImportState{ - Addr: addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "foo", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - ID: "bar", - ResolvedProvider: addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("aws"), - Module: addrs.RootModule, - }, - } - - diags := node.Execute(ctx, walkImport) - if diags.HasErrors() { - t.Fatalf("Unexpected error: %s", diags.Err()) - } - - if len(node.states) != 1 { - t.Fatalf("Wrong result! Expected one imported resource, got %d", len(node.states)) - } - // Verify the ID for good measure - id := node.states[0].State.GetAttr("id") - if !id.RawEquals(cty.StringVal("bar")) { - t.Fatalf("Wrong result! Expected id \"bar\", got %q", id.AsString()) - } -} - -func TestGraphNodeImportStateSubExecute(t *testing.T) { - state := states.NewState() - provider := testProvider("aws") - provider.ConfigureProvider(providers.ConfigureProviderRequest{}) - ctx := &MockEvalContext{ - StateState: state.SyncWrapper(), - ProviderProvider: provider, - ProviderSchemaSchema: &ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - }, - }, - }, - }, - } - - importedResource := providers.ImportedResource{ - TypeName: "aws_instance", - State: cty.ObjectVal(map[string]cty.Value{"id": cty.StringVal("bar")}), - } - - node := graphNodeImportStateSub{ - TargetAddr: addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "foo", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - State: importedResource, - ResolvedProvider: addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("aws"), - Module: addrs.RootModule, - }, - } - diags := node.Execute(ctx, walkImport) - if diags.HasErrors() { - t.Fatalf("Unexpected error: %s", diags.Err()) - } - - // check for resource in state - actual := strings.TrimSpace(state.String()) - expected := `aws_instance.foo: - ID = bar - provider = provider["registry.terraform.io/hashicorp/aws"]` - if actual != expected { - t.Fatalf("bad state after import: \n%s", actual) - } -} - -func TestGraphNodeImportStateSubExecuteNull(t *testing.T) { - state := states.NewState() - provider := testProvider("aws") - provider.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) { - // return null indicating that the requested resource does not exist - resp.NewState = cty.NullVal(cty.Object(map[string]cty.Type{ - "id": cty.String, - })) - return resp - } - - ctx := &MockEvalContext{ - StateState: state.SyncWrapper(), - ProviderProvider: provider, - ProviderSchemaSchema: &ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "id": { - Type: cty.String, - Computed: true, - }, - }, - }, - }, - }, - } - - importedResource := providers.ImportedResource{ - TypeName: "aws_instance", - State: cty.ObjectVal(map[string]cty.Value{"id": cty.StringVal("bar")}), - } - - node := graphNodeImportStateSub{ - TargetAddr: addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "foo", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - State: importedResource, - ResolvedProvider: addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("aws"), - Module: addrs.RootModule, - }, - } - diags := node.Execute(ctx, walkImport) - if !diags.HasErrors() { - t.Fatal("expected error for non-existent resource") - } -} diff --git a/internal/terraform/transform_local.go b/internal/terraform/transform_local.go deleted file mode 100644 index 667d6f917e00..000000000000 --- a/internal/terraform/transform_local.go +++ /dev/null @@ -1,42 +0,0 @@ -package terraform - -import ( - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" -) - -// LocalTransformer is a GraphTransformer that adds all the local values -// from the configuration to the graph. -type LocalTransformer struct { - Config *configs.Config -} - -func (t *LocalTransformer) Transform(g *Graph) error { - return t.transformModule(g, t.Config) -} - -func (t *LocalTransformer) transformModule(g *Graph, c *configs.Config) error { - if c == nil { - // Can't have any locals if there's no config - return nil - } - - for _, local := range c.Module.Locals { - addr := addrs.LocalValue{Name: local.Name} - node := &nodeExpandLocal{ - Addr: addr, - Module: c.Path, - Config: local, - } - g.Add(node) - } - - // Also populate locals for child modules - for _, cc := range c.Children { - if err := t.transformModule(g, cc); err != nil { - return err - } - } - - return nil -} diff --git a/internal/terraform/transform_module_expansion.go b/internal/terraform/transform_module_expansion.go deleted file mode 100644 index a4d45d963cd7..000000000000 --- a/internal/terraform/transform_module_expansion.go +++ /dev/null @@ -1,146 +0,0 @@ -package terraform - -import ( - "log" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/dag" -) - -// ModuleExpansionTransformer is a GraphTransformer that adds graph nodes -// representing the possible expansion of each module call in the configuration, -// and ensures that any nodes representing objects declared within a module -// are dependent on the expansion node so that they will be visited only -// after the module expansion has been decided. -// -// This transform must be applied only after all nodes representing objects -// that can be contained within modules have already been added. -type ModuleExpansionTransformer struct { - Config *configs.Config - - // Concrete allows injection of a wrapped module node by the graph builder - // to alter the evaluation behavior. - Concrete ConcreteModuleNodeFunc - - closers map[string]*nodeCloseModule -} - -func (t *ModuleExpansionTransformer) Transform(g *Graph) error { - t.closers = make(map[string]*nodeCloseModule) - // The root module is always a singleton and so does not need expansion - // processing, but any descendent modules do. We'll process them - // recursively using t.transform. - for _, cfg := range t.Config.Children { - err := t.transform(g, cfg, nil) - if err != nil { - return err - } - } - - // Now go through and connect all nodes to their respective module closers. - // This is done all at once here, because orphaned modules were already - // handled by the RemovedModuleTransformer, and those module closers are in - // the graph already, and need to be connected to their parent closers. - for _, v := range g.Vertices() { - switch v.(type) { - case GraphNodeDestroyer: - // Destroy nodes can only be ordered relative to other resource - // instances. - continue - case *nodeCloseModule: - // a module closer cannot connect to itself - continue - } - - // any node that executes within the scope of a module should be a - // GraphNodeModulePath - pather, ok := v.(GraphNodeModulePath) - if !ok { - continue - } - if closer, ok := t.closers[pather.ModulePath().String()]; ok { - // The module closer depends on each child resource instance, since - // during apply the module expansion will complete before the - // individual instances are applied. - g.Connect(dag.BasicEdge(closer, v)) - } - } - - // Modules implicitly depend on their child modules, so connect closers to - // other which contain their path. - for _, c := range t.closers { - for _, d := range t.closers { - if len(d.Addr) > len(c.Addr) && c.Addr.Equal(d.Addr[:len(c.Addr)]) { - g.Connect(dag.BasicEdge(c, d)) - } - } - } - - return nil -} - -func (t *ModuleExpansionTransformer) transform(g *Graph, c *configs.Config, parentNode dag.Vertex) error { - _, call := c.Path.Call() - modCall := c.Parent.Module.ModuleCalls[call.Name] - - n := &nodeExpandModule{ - Addr: c.Path, - Config: c.Module, - ModuleCall: modCall, - } - var expander dag.Vertex = n - if t.Concrete != nil { - expander = t.Concrete(n) - } - - g.Add(expander) - log.Printf("[TRACE] ModuleExpansionTransformer: Added %s as %T", c.Path, expander) - - if parentNode != nil { - log.Printf("[TRACE] ModuleExpansionTransformer: %s must wait for expansion of %s", dag.VertexName(expander), dag.VertexName(parentNode)) - g.Connect(dag.BasicEdge(expander, parentNode)) - } - - // Add the closer (which acts as the root module node) to provide a - // single exit point for the expanded module. - closer := &nodeCloseModule{ - Addr: c.Path, - } - g.Add(closer) - g.Connect(dag.BasicEdge(closer, expander)) - t.closers[c.Path.String()] = closer - - for _, childV := range g.Vertices() { - // don't connect a node to itself - if childV == expander { - continue - } - - var path addrs.Module - switch t := childV.(type) { - case GraphNodeDestroyer: - // skip destroyers, as they can only depend on other resources. - continue - - case GraphNodeModulePath: - path = t.ModulePath() - default: - continue - } - - if path.Equal(c.Path) { - log.Printf("[TRACE] ModuleExpansionTransformer: %s must wait for expansion of %s", dag.VertexName(childV), c.Path) - g.Connect(dag.BasicEdge(childV, expander)) - } - } - - // Also visit child modules, recursively. - for _, cc := range c.Children { - if err := t.transform(g, cc, expander); err != nil { - return err - } - } - - return nil -} diff --git a/internal/terraform/transform_module_variable.go b/internal/terraform/transform_module_variable.go deleted file mode 100644 index a9fa02c4e10d..000000000000 --- a/internal/terraform/transform_module_variable.go +++ /dev/null @@ -1,112 +0,0 @@ -package terraform - -import ( - "fmt" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/tfdiags" - "github.com/zclconf/go-cty/cty" - - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/configs" -) - -// ModuleVariableTransformer is a GraphTransformer that adds all the variables -// in the configuration to the graph. -// -// Any "variable" block present in any non-root module is included here, even -// if a particular variable is not referenced from anywhere. -// -// The transform will produce errors if a call to a module does not conform -// to the expected set of arguments, but this transformer is not in a good -// position to return errors and so the validate walk should include specific -// steps for validating module blocks, separate from this transform. -type ModuleVariableTransformer struct { - Config *configs.Config -} - -func (t *ModuleVariableTransformer) Transform(g *Graph) error { - return t.transform(g, nil, t.Config) -} - -func (t *ModuleVariableTransformer) transform(g *Graph, parent, c *configs.Config) error { - // We can have no variables if we have no configuration. - if c == nil { - return nil - } - - // Transform all the children first. - for _, cc := range c.Children { - if err := t.transform(g, c, cc); err != nil { - return err - } - } - - // If we're processing anything other than the root module then we'll - // add graph nodes for variables defined inside. (Variables for the root - // module are dealt with in RootVariableTransformer). - // If we have a parent, we can determine if a module variable is being - // used, so we transform this. - if parent != nil { - if err := t.transformSingle(g, parent, c); err != nil { - return err - } - } - - return nil -} - -func (t *ModuleVariableTransformer) transformSingle(g *Graph, parent, c *configs.Config) error { - _, call := c.Path.Call() - - // Find the call in the parent module configuration, so we can get the - // expressions given for each input variable at the call site. - callConfig, exists := parent.Module.ModuleCalls[call.Name] - if !exists { - // This should never happen, since it indicates an improperly-constructed - // configuration tree. - panic(fmt.Errorf("no module call block found for %s", c.Path)) - } - - // We need to construct a schema for the expected call arguments based on - // the configured variables in our config, which we can then use to - // decode the content of the call block. - schema := &hcl.BodySchema{} - for _, v := range c.Module.Variables { - schema.Attributes = append(schema.Attributes, hcl.AttributeSchema{ - Name: v.Name, - Required: v.Default == cty.NilVal, - }) - } - - content, contentDiags := callConfig.Config.Content(schema) - if contentDiags.HasErrors() { - // Validation code elsewhere should deal with any errors before we - // get in here, but we'll report them out here just in case, to - // avoid crashes. - var diags tfdiags.Diagnostics - diags = diags.Append(contentDiags) - return diags.Err() - } - - for _, v := range c.Module.Variables { - var expr hcl.Expression - if attr := content.Attributes[v.Name]; attr != nil { - expr = attr.Expr - } - - // Add a plannable node, as the variable may expand - // during module expansion - node := &nodeExpandModuleVariable{ - Addr: addrs.InputVariable{ - Name: v.Name, - }, - Module: c.Path, - Config: v, - Expr: expr, - } - g.Add(node) - } - - return nil -} diff --git a/internal/terraform/transform_module_variable_test.go b/internal/terraform/transform_module_variable_test.go deleted file mode 100644 index 363d141ae7cc..000000000000 --- a/internal/terraform/transform_module_variable_test.go +++ /dev/null @@ -1,67 +0,0 @@ -package terraform - -import ( - "strings" - "testing" - - "github.com/hashicorp/terraform/internal/addrs" -) - -func TestModuleVariableTransformer(t *testing.T) { - g := Graph{Path: addrs.RootModuleInstance} - module := testModule(t, "transform-module-var-basic") - - { - tf := &RootVariableTransformer{Config: module} - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - } - - { - tf := &ModuleVariableTransformer{Config: module} - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(testTransformModuleVarBasicStr) - if actual != expected { - t.Fatalf("bad:\n\n%s", actual) - } -} - -func TestModuleVariableTransformer_nested(t *testing.T) { - g := Graph{Path: addrs.RootModuleInstance} - module := testModule(t, "transform-module-var-nested") - - { - tf := &RootVariableTransformer{Config: module} - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - } - - { - tf := &ModuleVariableTransformer{Config: module} - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(testTransformModuleVarNestedStr) - if actual != expected { - t.Fatalf("bad:\n\n%s", actual) - } -} - -const testTransformModuleVarBasicStr = ` -module.child.var.value (expand) -` - -const testTransformModuleVarNestedStr = ` -module.child.module.child.var.value (expand) -module.child.var.value (expand) -` diff --git a/internal/terraform/transform_orphan_count.go b/internal/terraform/transform_orphan_count.go deleted file mode 100644 index bdeebf6d18a3..000000000000 --- a/internal/terraform/transform_orphan_count.go +++ /dev/null @@ -1,61 +0,0 @@ -package terraform - -import ( - "log" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/dag" - "github.com/hashicorp/terraform/internal/states" -) - -// OrphanResourceInstanceCountTransformer is a GraphTransformer that adds orphans -// for an expanded count to the graph. The determination of this depends -// on the count argument given. -// -// Orphans are found by comparing the count to what is found in the state. -// This transform assumes that if an element in the state is within the count -// bounds given, that it is not an orphan. -type OrphanResourceInstanceCountTransformer struct { - Concrete ConcreteResourceInstanceNodeFunc - - Addr addrs.AbsResource // Addr of the resource to look for orphans - InstanceAddrs []addrs.AbsResourceInstance // Addresses that currently exist in config - State *states.State // Full global state -} - -func (t *OrphanResourceInstanceCountTransformer) Transform(g *Graph) error { - rs := t.State.Resource(t.Addr) - if rs == nil { - return nil // Resource doesn't exist in state, so nothing to do! - } - - // This is an O(n*m) analysis, which we accept for now because the - // number of instances of a single resource ought to always be small in any - // reasonable Terraform configuration. -Have: - for key, inst := range rs.Instances { - // Instances which have no current objects (only one or more - // deposed objects) will be taken care of separately - if inst.Current == nil { - continue - } - - thisAddr := rs.Addr.Instance(key) - for _, wantAddr := range t.InstanceAddrs { - if wantAddr.Equal(thisAddr) { - continue Have - } - } - // If thisAddr is not in t.InstanceAddrs then we've found an "orphan" - - abstract := NewNodeAbstractResourceInstance(thisAddr) - var node dag.Vertex = abstract - if f := t.Concrete; f != nil { - node = f(abstract) - } - log.Printf("[TRACE] OrphanResourceInstanceCountTransformer: adding %s as %T", thisAddr, node) - g.Add(node) - } - - return nil -} diff --git a/internal/terraform/transform_orphan_count_test.go b/internal/terraform/transform_orphan_count_test.go deleted file mode 100644 index 024189b9a40d..000000000000 --- a/internal/terraform/transform_orphan_count_test.go +++ /dev/null @@ -1,306 +0,0 @@ -package terraform - -import ( - "strings" - "testing" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/states" -) - -func TestOrphanResourceCountTransformer(t *testing.T) { - state := states.NewState() - root := state.RootModule() - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.web").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[0]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[2]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - g := Graph{Path: addrs.RootModuleInstance} - - { - tf := &OrphanResourceInstanceCountTransformer{ - Concrete: testOrphanResourceConcreteFunc, - Addr: addrs.RootModuleInstance.Resource( - addrs.ManagedResourceMode, "aws_instance", "foo", - ), - InstanceAddrs: []addrs.AbsResourceInstance{mustResourceInstanceAddr("aws_instance.foo[0]")}, - State: state, - } - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(testTransformOrphanResourceCountBasicStr) - if actual != expected { - t.Fatalf("bad:\n\n%s", actual) - } -} - -func TestOrphanResourceCountTransformer_zero(t *testing.T) { - state := states.NewState() - root := state.RootModule() - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.web").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[0]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[2]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - g := Graph{Path: addrs.RootModuleInstance} - - { - tf := &OrphanResourceInstanceCountTransformer{ - Concrete: testOrphanResourceConcreteFunc, - Addr: addrs.RootModuleInstance.Resource( - addrs.ManagedResourceMode, "aws_instance", "foo", - ), - InstanceAddrs: []addrs.AbsResourceInstance{}, - State: state, - } - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(testTransformOrphanResourceCountZeroStr) - if actual != expected { - t.Fatalf("bad:\n\n%s", actual) - } -} - -func TestOrphanResourceCountTransformer_oneIndex(t *testing.T) { - state := states.NewState() - root := state.RootModule() - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.web").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[0]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[1]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - g := Graph{Path: addrs.RootModuleInstance} - - { - tf := &OrphanResourceInstanceCountTransformer{ - Concrete: testOrphanResourceConcreteFunc, - Addr: addrs.RootModuleInstance.Resource( - addrs.ManagedResourceMode, "aws_instance", "foo", - ), - InstanceAddrs: []addrs.AbsResourceInstance{mustResourceInstanceAddr("aws_instance.foo[0]")}, - State: state, - } - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(testTransformOrphanResourceCountOneIndexStr) - if actual != expected { - t.Fatalf("bad:\n\n%s", actual) - } -} - -func TestOrphanResourceCountTransformer_deposed(t *testing.T) { - state := states.NewState() - root := state.RootModule() - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.web").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[0]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceCurrent( - mustResourceInstanceAddr("aws_instance.foo[1]").Resource, - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - root.SetResourceInstanceDeposed( - mustResourceInstanceAddr("aws_instance.foo[2]").Resource, - states.NewDeposedKey(), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo"}`), - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - g := Graph{Path: addrs.RootModuleInstance} - - { - tf := &OrphanResourceInstanceCountTransformer{ - Concrete: testOrphanResourceConcreteFunc, - Addr: addrs.RootModuleInstance.Resource( - addrs.ManagedResourceMode, "aws_instance", "foo", - ), - InstanceAddrs: []addrs.AbsResourceInstance{mustResourceInstanceAddr("aws_instance.foo[0]")}, - State: state, - } - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(testTransformOrphanResourceCountDeposedStr) - if actual != expected { - t.Fatalf("bad:\n\n%s", actual) - } -} - -// When converting from a NoEach mode to an EachMap via a switch to for_each, -// an edge is necessary to ensure that the map-key'd instances -// are evaluated after the NoKey resource, because the final instance evaluated -// sets the whole resource's EachMode. -func TestOrphanResourceCountTransformer_ForEachEdgesAdded(t *testing.T) { - state := states.BuildState(func(s *states.SyncState) { - // "bar" key'd resource - s.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "foo", - }.Instance(addrs.StringKey("bar")).Absolute(addrs.RootModuleInstance), - &states.ResourceInstanceObjectSrc{ - AttrsFlat: map[string]string{ - "id": "foo", - }, - Status: states.ObjectReady, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - - // NoKey'd resource - s.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "foo", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - &states.ResourceInstanceObjectSrc{ - AttrsFlat: map[string]string{ - "id": "foo", - }, - Status: states.ObjectReady, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), - ) - }) - - g := Graph{Path: addrs.RootModuleInstance} - - { - tf := &OrphanResourceInstanceCountTransformer{ - Concrete: testOrphanResourceConcreteFunc, - Addr: addrs.RootModuleInstance.Resource( - addrs.ManagedResourceMode, "aws_instance", "foo", - ), - InstanceAddrs: []addrs.AbsResourceInstance{}, - State: state, - } - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(testTransformOrphanResourceForEachStr) - if actual != expected { - t.Fatalf("bad:\n\n%s", actual) - } -} - -const testTransformOrphanResourceCountBasicStr = ` -aws_instance.foo[2] (orphan) -` - -const testTransformOrphanResourceCountZeroStr = ` -aws_instance.foo[0] (orphan) -aws_instance.foo[2] (orphan) -` - -const testTransformOrphanResourceCountOneIndexStr = ` -aws_instance.foo[1] (orphan) -` - -const testTransformOrphanResourceCountDeposedStr = ` -aws_instance.foo[1] (orphan) -` - -const testTransformOrphanResourceForEachStr = ` -aws_instance.foo (orphan) -aws_instance.foo["bar"] (orphan) -` diff --git a/internal/terraform/transform_orphan_output.go b/internal/terraform/transform_orphan_output.go deleted file mode 100644 index fe3e9ce4192d..000000000000 --- a/internal/terraform/transform_orphan_output.go +++ /dev/null @@ -1,62 +0,0 @@ -package terraform - -import ( - "log" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/states" -) - -// OrphanOutputTransformer finds the outputs that aren't present -// in the given config that are in the state and adds them to the graph -// for deletion. -type OrphanOutputTransformer struct { - Config *configs.Config // Root of config tree - State *states.State // State is the root state - Planning bool -} - -func (t *OrphanOutputTransformer) Transform(g *Graph) error { - if t.State == nil { - log.Printf("[DEBUG] No state, no orphan outputs") - return nil - } - - for _, ms := range t.State.Modules { - if err := t.transform(g, ms); err != nil { - return err - } - } - return nil -} - -func (t *OrphanOutputTransformer) transform(g *Graph, ms *states.Module) error { - if ms == nil { - return nil - } - - moduleAddr := ms.Addr - - // Get the config for this path, which is nil if the entire module has been - // removed. - var outputs map[string]*configs.Output - if c := t.Config.DescendentForInstance(moduleAddr); c != nil { - outputs = c.Module.Outputs - } - - // An output is "orphaned" if it's present in the state but not declared - // in the configuration. - for name := range ms.OutputValues { - if _, exists := outputs[name]; exists { - continue - } - - g.Add(&NodeDestroyableOutput{ - Addr: addrs.OutputValue{Name: name}.Absolute(moduleAddr), - Planning: t.Planning, - }) - } - - return nil -} diff --git a/internal/terraform/transform_orphan_resource.go b/internal/terraform/transform_orphan_resource.go deleted file mode 100644 index 348ae905205d..000000000000 --- a/internal/terraform/transform_orphan_resource.go +++ /dev/null @@ -1,108 +0,0 @@ -package terraform - -import ( - "log" - - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/dag" - "github.com/hashicorp/terraform/internal/states" -) - -// OrphanResourceInstanceTransformer is a GraphTransformer that adds orphaned -// resource instances to the graph. An "orphan" is an instance that is present -// in the state but belongs to a resource that is no longer present in the -// configuration. -// -// This is not the transformer that deals with "count orphans" (instances that -// are no longer covered by a resource's "count" or "for_each" setting); that's -// handled instead by OrphanResourceCountTransformer. -type OrphanResourceInstanceTransformer struct { - Concrete ConcreteResourceInstanceNodeFunc - - // State is the global state. We require the global state to - // properly find module orphans at our path. - State *states.State - - // Config is the root node in the configuration tree. We'll look up - // the appropriate note in this tree using the path in each node. - Config *configs.Config - - // Do not apply this transformer - skip bool -} - -func (t *OrphanResourceInstanceTransformer) Transform(g *Graph) error { - if t.skip { - return nil - } - - if t.State == nil { - // If the entire state is nil, there can't be any orphans - return nil - } - if t.Config == nil { - // Should never happen: we can't be doing any Terraform operations - // without at least an empty configuration. - panic("OrphanResourceInstanceTransformer used without setting Config") - } - - // Go through the modules and for each module transform in order - // to add the orphan. - for _, ms := range t.State.Modules { - if err := t.transform(g, ms); err != nil { - return err - } - } - - return nil -} - -func (t *OrphanResourceInstanceTransformer) transform(g *Graph, ms *states.Module) error { - if ms == nil { - return nil - } - - moduleAddr := ms.Addr - - // Get the configuration for this module. The configuration might be - // nil if the module was removed from the configuration. This is okay, - // this just means that every resource is an orphan. - var m *configs.Module - if c := t.Config.DescendentForInstance(moduleAddr); c != nil { - m = c.Module - } - - // An "orphan" is a resource that is in the state but not the configuration, - // so we'll walk the state resources and try to correlate each of them - // with a configuration block. Each orphan gets a node in the graph whose - // type is decided by t.Concrete. - // - // We don't handle orphans related to changes in the "count" and "for_each" - // pseudo-arguments here. They are handled by OrphanResourceCountTransformer. - for _, rs := range ms.Resources { - if m != nil { - if r := m.ResourceByAddr(rs.Addr.Resource); r != nil { - continue - } - } - - for key, inst := range rs.Instances { - // Instances which have no current objects (only one or more - // deposed objects) will be taken care of separately - if inst.Current == nil { - continue - } - - addr := rs.Addr.Instance(key) - abstract := NewNodeAbstractResourceInstance(addr) - var node dag.Vertex = abstract - if f := t.Concrete; f != nil { - node = f(abstract) - } - log.Printf("[TRACE] OrphanResourceInstanceTransformer: adding single-instance orphan node for %s", addr) - g.Add(node) - } - } - - return nil -} diff --git a/internal/terraform/transform_orphan_resource_test.go b/internal/terraform/transform_orphan_resource_test.go deleted file mode 100644 index f44f081525f0..000000000000 --- a/internal/terraform/transform_orphan_resource_test.go +++ /dev/null @@ -1,326 +0,0 @@ -package terraform - -import ( - "fmt" - "strings" - "testing" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/dag" - "github.com/hashicorp/terraform/internal/states" -) - -func TestOrphanResourceInstanceTransformer(t *testing.T) { - mod := testModule(t, "transform-orphan-basic") - - state := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "web", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - &states.ResourceInstanceObjectSrc{ - AttrsFlat: map[string]string{ - "id": "foo", - }, - Status: states.ObjectReady, - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("aws"), - Module: addrs.RootModule, - }, - ) - - // The orphan - s.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "db", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - &states.ResourceInstanceObjectSrc{ - AttrsFlat: map[string]string{ - "id": "foo", - }, - Status: states.ObjectReady, - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("aws"), - Module: addrs.RootModule, - }, - ) - - // A deposed orphan should not be handled by this transformer - s.SetResourceInstanceDeposed( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_instance", - Name: "deposed", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - states.NewDeposedKey(), - &states.ResourceInstanceObjectSrc{ - AttrsFlat: map[string]string{ - "id": "foo", - }, - Status: states.ObjectReady, - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("test"), - Module: addrs.RootModule, - }, - ) - }) - - g := Graph{Path: addrs.RootModuleInstance} - { - tf := &ConfigTransformer{Config: mod} - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - } - - { - tf := &OrphanResourceInstanceTransformer{ - Concrete: testOrphanResourceConcreteFunc, - State: state, - Config: mod, - } - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(testTransformOrphanResourceBasicStr) - if actual != expected { - t.Fatalf("bad:\n\n%s", actual) - } -} - -func TestOrphanResourceInstanceTransformer_countGood(t *testing.T) { - mod := testModule(t, "transform-orphan-count") - - state := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "foo", - }.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance), - &states.ResourceInstanceObjectSrc{ - AttrsFlat: map[string]string{ - "id": "foo", - }, - Status: states.ObjectReady, - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("aws"), - Module: addrs.RootModule, - }, - ) - s.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "foo", - }.Instance(addrs.IntKey(1)).Absolute(addrs.RootModuleInstance), - &states.ResourceInstanceObjectSrc{ - AttrsFlat: map[string]string{ - "id": "foo", - }, - Status: states.ObjectReady, - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("aws"), - Module: addrs.RootModule, - }, - ) - }) - - g := Graph{Path: addrs.RootModuleInstance} - { - tf := &ConfigTransformer{Config: mod} - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - } - - { - tf := &OrphanResourceInstanceTransformer{ - Concrete: testOrphanResourceConcreteFunc, - State: state, - Config: mod, - } - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(testTransformOrphanResourceCountStr) - if actual != expected { - t.Fatalf("bad:\n\n%s", actual) - } -} - -func TestOrphanResourceInstanceTransformer_countBad(t *testing.T) { - mod := testModule(t, "transform-orphan-count-empty") - state := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "foo", - }.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance), - &states.ResourceInstanceObjectSrc{ - AttrsFlat: map[string]string{ - "id": "foo", - }, - Status: states.ObjectReady, - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("aws"), - Module: addrs.RootModule, - }, - ) - s.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "foo", - }.Instance(addrs.IntKey(1)).Absolute(addrs.RootModuleInstance), - &states.ResourceInstanceObjectSrc{ - AttrsFlat: map[string]string{ - "id": "foo", - }, - Status: states.ObjectReady, - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("aws"), - Module: addrs.RootModule, - }, - ) - }) - - g := Graph{Path: addrs.RootModuleInstance} - { - tf := &ConfigTransformer{Config: mod} - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - } - - { - tf := &OrphanResourceInstanceTransformer{ - Concrete: testOrphanResourceConcreteFunc, - State: state, - Config: mod, - } - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(testTransformOrphanResourceCountBadStr) - if actual != expected { - t.Fatalf("bad:\n\n%s", actual) - } -} - -func TestOrphanResourceInstanceTransformer_modules(t *testing.T) { - mod := testModule(t, "transform-orphan-modules") - state := states.BuildState(func(s *states.SyncState) { - s.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "foo", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - &states.ResourceInstanceObjectSrc{ - AttrsFlat: map[string]string{ - "id": "foo", - }, - Status: states.ObjectReady, - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("aws"), - Module: addrs.RootModule, - }, - ) - s.SetResourceInstanceCurrent( - addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "web", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance.Child("child", addrs.NoKey)), - &states.ResourceInstanceObjectSrc{ - AttrsFlat: map[string]string{ - "id": "foo", - }, - Status: states.ObjectReady, - }, - addrs.AbsProviderConfig{ - Provider: addrs.NewDefaultProvider("aws"), - Module: addrs.RootModule, - }, - ) - }) - - g := Graph{Path: addrs.RootModuleInstance} - { - tf := &ConfigTransformer{Config: mod} - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - } - - { - tf := &OrphanResourceInstanceTransformer{ - Concrete: testOrphanResourceConcreteFunc, - State: state, - Config: mod, - } - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - } - - got := strings.TrimSpace(g.String()) - want := strings.TrimSpace(testTransformOrphanResourceModulesStr) - if got != want { - t.Fatalf("wrong state result\ngot:\n%s\n\nwant:\n%s", got, want) - } -} - -const testTransformOrphanResourceBasicStr = ` -aws_instance.db (orphan) -aws_instance.web -` - -const testTransformOrphanResourceCountStr = ` -aws_instance.foo -` - -const testTransformOrphanResourceCountBadStr = ` -aws_instance.foo[0] (orphan) -aws_instance.foo[1] (orphan) -` - -const testTransformOrphanResourceModulesStr = ` -aws_instance.foo -module.child.aws_instance.web (orphan) -` - -func testOrphanResourceConcreteFunc(a *NodeAbstractResourceInstance) dag.Vertex { - return &testOrphanResourceInstanceConcrete{a} -} - -type testOrphanResourceInstanceConcrete struct { - *NodeAbstractResourceInstance -} - -func (n *testOrphanResourceInstanceConcrete) Name() string { - return fmt.Sprintf("%s (orphan)", n.NodeAbstractResourceInstance.Name()) -} diff --git a/internal/terraform/transform_output.go b/internal/terraform/transform_output.go deleted file mode 100644 index 214bc3ff10ec..000000000000 --- a/internal/terraform/transform_output.go +++ /dev/null @@ -1,73 +0,0 @@ -package terraform - -import ( - "log" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" -) - -// OutputTransformer is a GraphTransformer that adds all the outputs -// in the configuration to the graph. -// -// This is done for the apply graph builder even if dependent nodes -// aren't changing since there is no downside: the state will be available -// even if the dependent items aren't changing. -type OutputTransformer struct { - Config *configs.Config - - // Refresh-only mode means that any failing output preconditions are - // reported as warnings rather than errors - RefreshOnly bool - - // Planning must be set to true only when we're building a planning graph. - // It must be set to false whenever we're building an apply graph. - Planning bool - - // If this is a planned destroy, root outputs are still in the configuration - // so we need to record that we wish to remove them - PlanDestroy bool - - // ApplyDestroy indicates that this is being added to an apply graph, which - // is the result of a destroy plan. - ApplyDestroy bool -} - -func (t *OutputTransformer) Transform(g *Graph) error { - return t.transform(g, t.Config) -} - -func (t *OutputTransformer) transform(g *Graph, c *configs.Config) error { - // If we have no config then there can be no outputs. - if c == nil { - return nil - } - - // Transform all the children. We must do this first because - // we can reference module outputs and they must show up in the - // reference map. - for _, cc := range c.Children { - if err := t.transform(g, cc); err != nil { - return err - } - } - - for _, o := range c.Module.Outputs { - addr := addrs.OutputValue{Name: o.Name} - - node := &nodeExpandOutput{ - Addr: addr, - Module: c.Path, - Config: o, - PlanDestroy: t.PlanDestroy, - ApplyDestroy: t.ApplyDestroy, - RefreshOnly: t.RefreshOnly, - Planning: t.Planning, - } - - log.Printf("[TRACE] OutputTransformer: adding %s as %T", o.Name, node) - g.Add(node) - } - - return nil -} diff --git a/internal/terraform/transform_provider.go b/internal/terraform/transform_provider.go deleted file mode 100644 index 2e1f8bd5f3f8..000000000000 --- a/internal/terraform/transform_provider.go +++ /dev/null @@ -1,730 +0,0 @@ -package terraform - -import ( - "fmt" - "log" - - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/dag" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -func transformProviders(concrete ConcreteProviderNodeFunc, config *configs.Config) GraphTransformer { - return GraphTransformMulti( - // Add providers from the config - &ProviderConfigTransformer{ - Config: config, - Concrete: concrete, - }, - // Add any remaining missing providers - &MissingProviderTransformer{ - Config: config, - Concrete: concrete, - }, - // Connect the providers - &ProviderTransformer{ - Config: config, - }, - // Remove unused providers and proxies - &PruneProviderTransformer{}, - ) -} - -// GraphNodeProvider is an interface that nodes that can be a provider -// must implement. -// -// ProviderAddr returns the address of the provider configuration this -// satisfies, which is relative to the path returned by method Path(). -// -// Name returns the full name of the provider in the config. -type GraphNodeProvider interface { - GraphNodeModulePath - ProviderAddr() addrs.AbsProviderConfig - Name() string -} - -// GraphNodeCloseProvider is an interface that nodes that can be a close -// provider must implement. The CloseProviderName returned is the name of -// the provider they satisfy. -type GraphNodeCloseProvider interface { - GraphNodeModulePath - CloseProviderAddr() addrs.AbsProviderConfig -} - -// GraphNodeProviderConsumer is an interface that nodes that require -// a provider must implement. ProvidedBy must return the address of the provider -// to use, which will be resolved to a configuration either in the same module -// or in an ancestor module, with the resulting absolute address passed to -// SetProvider. -type GraphNodeProviderConsumer interface { - GraphNodeModulePath - // ProvidedBy returns the address of the provider configuration the node - // refers to, if available. The following value types may be returned: - // - // nil + exact true: the node does not require a provider - // * addrs.LocalProviderConfig: the provider was set in the resource config - // * addrs.AbsProviderConfig + exact true: the provider configuration was - // taken from the instance state. - // * addrs.AbsProviderConfig + exact false: no config or state; the returned - // value is a default provider configuration address for the resource's - // Provider - ProvidedBy() (addr addrs.ProviderConfig, exact bool) - - // Provider() returns the Provider FQN for the node. - Provider() (provider addrs.Provider) - - // Set the resolved provider address for this resource. - SetProvider(addrs.AbsProviderConfig) -} - -// ProviderTransformer is a GraphTransformer that maps resources to providers -// within the graph. This will error if there are any resources that don't map -// to proper resources. -type ProviderTransformer struct { - Config *configs.Config -} - -func (t *ProviderTransformer) Transform(g *Graph) error { - // We need to find a provider configuration address for each resource - // either directly represented by a node or referenced by a node in - // the graph, and then create graph edges from provider to provider user - // so that the providers will get initialized first. - - var diags tfdiags.Diagnostics - - // To start, we'll collect the _requested_ provider addresses for each - // node, which we'll then resolve (handling provider inheritence, etc) in - // the next step. - // Our "requested" map is from graph vertices to string representations of - // provider config addresses (for deduping) to requests. - type ProviderRequest struct { - Addr addrs.AbsProviderConfig - Exact bool // If true, inheritence from parent modules is not attempted - } - requested := map[dag.Vertex]map[string]ProviderRequest{} - needConfigured := map[string]addrs.AbsProviderConfig{} - for _, v := range g.Vertices() { - // Does the vertex _directly_ use a provider? - if pv, ok := v.(GraphNodeProviderConsumer); ok { - providerAddr, exact := pv.ProvidedBy() - if providerAddr == nil && exact { - // no provider is required - continue - } - - requested[v] = make(map[string]ProviderRequest) - - var absPc addrs.AbsProviderConfig - - switch p := providerAddr.(type) { - case addrs.AbsProviderConfig: - // ProvidedBy() returns an AbsProviderConfig when the provider - // configuration is set in state, so we do not need to verify - // the FQN matches. - absPc = p - - if exact { - log.Printf("[TRACE] ProviderTransformer: %s is provided by %s exactly", dag.VertexName(v), absPc) - } - - case addrs.LocalProviderConfig: - // ProvidedBy() return a LocalProviderConfig when the resource - // contains a `provider` attribute - absPc.Provider = pv.Provider() - modPath := pv.ModulePath() - if t.Config == nil { - absPc.Module = modPath - absPc.Alias = p.Alias - break - } - - absPc.Module = modPath - absPc.Alias = p.Alias - - default: - // This should never happen; the case statements are meant to be exhaustive - panic(fmt.Sprintf("%s: provider for %s couldn't be determined", dag.VertexName(v), absPc)) - } - - requested[v][absPc.String()] = ProviderRequest{ - Addr: absPc, - Exact: exact, - } - - // Direct references need the provider configured as well as initialized - needConfigured[absPc.String()] = absPc - } - } - - // Now we'll go through all the requested addresses we just collected and - // figure out which _actual_ config address each belongs to, after resolving - // for provider inheritance and passing. - m := providerVertexMap(g) - for v, reqs := range requested { - for key, req := range reqs { - p := req.Addr - target := m[key] - - _, ok := v.(GraphNodeModulePath) - if !ok && target == nil { - // No target and no path to traverse up from - diags = diags.Append(fmt.Errorf("%s: provider %s couldn't be found", dag.VertexName(v), p)) - continue - } - - if target != nil { - log.Printf("[TRACE] ProviderTransformer: exact match for %s serving %s", p, dag.VertexName(v)) - } - - // if we don't have a provider at this level, walk up the path looking for one, - // unless we were told to be exact. - if target == nil && !req.Exact { - for pp, ok := p.Inherited(); ok; pp, ok = pp.Inherited() { - key := pp.String() - target = m[key] - if target != nil { - log.Printf("[TRACE] ProviderTransformer: %s uses inherited configuration %s", dag.VertexName(v), pp) - break - } - log.Printf("[TRACE] ProviderTransformer: looking for %s to serve %s", pp, dag.VertexName(v)) - } - } - - // If this provider doesn't need to be configured then we can just - // stub it out with an init-only provider node, which will just - // start up the provider and fetch its schema. - if _, exists := needConfigured[key]; target == nil && !exists { - stubAddr := addrs.AbsProviderConfig{ - Module: addrs.RootModule, - Provider: p.Provider, - } - stub := &NodeEvalableProvider{ - &NodeAbstractProvider{ - Addr: stubAddr, - }, - } - m[stubAddr.String()] = stub - log.Printf("[TRACE] ProviderTransformer: creating init-only node for %s", stubAddr) - target = stub - g.Add(target) - } - - if target == nil { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Provider configuration not present", - fmt.Sprintf( - "To work with %s its original provider configuration at %s is required, but it has been removed. This occurs when a provider configuration is removed while objects created by that provider still exist in the state. Re-add the provider configuration to destroy %s, after which you can remove the provider configuration again.", - dag.VertexName(v), p, dag.VertexName(v), - ), - )) - break - } - - // see if this is a proxy provider pointing to another concrete config - if p, ok := target.(*graphNodeProxyProvider); ok { - g.Remove(p) - target = p.Target() - } - - log.Printf("[DEBUG] ProviderTransformer: %q (%T) needs %s", dag.VertexName(v), v, dag.VertexName(target)) - if pv, ok := v.(GraphNodeProviderConsumer); ok { - pv.SetProvider(target.ProviderAddr()) - } - g.Connect(dag.BasicEdge(v, target)) - } - } - - return diags.Err() -} - -// CloseProviderTransformer is a GraphTransformer that adds nodes to the -// graph that will close open provider connections that aren't needed anymore. -// A provider connection is not needed anymore once all depended resources -// in the graph are evaluated. -type CloseProviderTransformer struct{} - -func (t *CloseProviderTransformer) Transform(g *Graph) error { - pm := providerVertexMap(g) - cpm := make(map[string]*graphNodeCloseProvider) - var err error - - for _, p := range pm { - key := p.ProviderAddr().String() - - // get the close provider of this type if we alread created it - closer := cpm[key] - - if closer == nil { - // create a closer for this provider type - closer = &graphNodeCloseProvider{Addr: p.ProviderAddr()} - g.Add(closer) - cpm[key] = closer - } - - // Close node depends on the provider itself - // this is added unconditionally, so it will connect to all instances - // of the provider. Extra edges will be removed by transitive - // reduction. - g.Connect(dag.BasicEdge(closer, p)) - - // connect all the provider's resources to the close node - for _, s := range g.UpEdges(p) { - if _, ok := s.(GraphNodeProviderConsumer); ok { - g.Connect(dag.BasicEdge(closer, s)) - } - } - } - - return err -} - -// MissingProviderTransformer is a GraphTransformer that adds to the graph -// a node for each default provider configuration that is referenced by another -// node but not already present in the graph. -// -// These "default" nodes are always added to the root module, regardless of -// where they are requested. This is important because our inheritance -// resolution behavior in ProviderTransformer will then treat these as a -// last-ditch fallback after walking up the tree, rather than preferring them -// as it would if they were placed in the same module as the requester. -// -// This transformer may create extra nodes that are not needed in practice, -// due to overriding provider configurations in child modules. -// PruneProviderTransformer can then remove these once ProviderTransformer -// has resolved all of the inheritence, etc. -type MissingProviderTransformer struct { - // MissingProviderTransformer needs the config to rule out _implied_ default providers - Config *configs.Config - - // Concrete, if set, overrides how the providers are made. - Concrete ConcreteProviderNodeFunc -} - -func (t *MissingProviderTransformer) Transform(g *Graph) error { - // Initialize factory - if t.Concrete == nil { - t.Concrete = func(a *NodeAbstractProvider) dag.Vertex { - return a - } - } - - var err error - m := providerVertexMap(g) - for _, v := range g.Vertices() { - pv, ok := v.(GraphNodeProviderConsumer) - if !ok { - continue - } - - // For our work here we actually care only about the provider type and - // we plan to place all default providers in the root module. - providerFqn := pv.Provider() - - // We're going to create an implicit _default_ configuration for the - // referenced provider type in the _root_ module, ignoring all other - // aspects of the resource's declared provider address. - defaultAddr := addrs.RootModuleInstance.ProviderConfigDefault(providerFqn) - key := defaultAddr.String() - provider := m[key] - - if provider != nil { - // There's already an explicit default configuration for this - // provider type in the root module, so we have nothing to do. - continue - } - - log.Printf("[DEBUG] adding implicit provider configuration %s, implied first by %s", defaultAddr, dag.VertexName(v)) - - // create the missing top-level provider - provider = t.Concrete(&NodeAbstractProvider{ - Addr: defaultAddr, - }).(GraphNodeProvider) - - g.Add(provider) - m[key] = provider - } - - return err -} - -// PruneProviderTransformer removes any providers that are not actually used by -// anything, and provider proxies. This avoids the provider being initialized -// and configured. This both saves resources but also avoids errors since -// configuration may imply initialization which may require auth. -type PruneProviderTransformer struct{} - -func (t *PruneProviderTransformer) Transform(g *Graph) error { - for _, v := range g.Vertices() { - // We only care about providers - _, ok := v.(GraphNodeProvider) - if !ok { - continue - } - - // ProxyProviders will have up edges, but we're now done with them in the graph - if _, ok := v.(*graphNodeProxyProvider); ok { - log.Printf("[DEBUG] pruning proxy %s", dag.VertexName(v)) - g.Remove(v) - } - - // Remove providers with no dependencies. - if g.UpEdges(v).Len() == 0 { - log.Printf("[DEBUG] pruning unused %s", dag.VertexName(v)) - g.Remove(v) - } - } - - return nil -} - -func providerVertexMap(g *Graph) map[string]GraphNodeProvider { - m := make(map[string]GraphNodeProvider) - for _, v := range g.Vertices() { - if pv, ok := v.(GraphNodeProvider); ok { - addr := pv.ProviderAddr() - m[addr.String()] = pv - } - } - - return m -} - -type graphNodeCloseProvider struct { - Addr addrs.AbsProviderConfig -} - -var ( - _ GraphNodeCloseProvider = (*graphNodeCloseProvider)(nil) - _ GraphNodeExecutable = (*graphNodeCloseProvider)(nil) -) - -func (n *graphNodeCloseProvider) Name() string { - return n.Addr.String() + " (close)" -} - -// GraphNodeModulePath -func (n *graphNodeCloseProvider) ModulePath() addrs.Module { - return n.Addr.Module -} - -// GraphNodeExecutable impl. -func (n *graphNodeCloseProvider) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) { - return diags.Append(ctx.CloseProvider(n.Addr)) -} - -func (n *graphNodeCloseProvider) CloseProviderAddr() addrs.AbsProviderConfig { - return n.Addr -} - -// GraphNodeDotter impl. -func (n *graphNodeCloseProvider) DotNode(name string, opts *dag.DotOpts) *dag.DotNode { - if !opts.Verbose { - return nil - } - return &dag.DotNode{ - Name: name, - Attrs: map[string]string{ - "label": n.Name(), - "shape": "diamond", - }, - } -} - -// graphNodeProxyProvider is a GraphNodeProvider implementation that is used to -// store the name and value of a provider node for inheritance between modules. -// These nodes are only used to store the data while loading the provider -// configurations, and are removed after all the resources have been connected -// to their providers. -type graphNodeProxyProvider struct { - addr addrs.AbsProviderConfig - target GraphNodeProvider -} - -var ( - _ GraphNodeModulePath = (*graphNodeProxyProvider)(nil) - _ GraphNodeProvider = (*graphNodeProxyProvider)(nil) -) - -func (n *graphNodeProxyProvider) ProviderAddr() addrs.AbsProviderConfig { - return n.addr -} - -func (n *graphNodeProxyProvider) ModulePath() addrs.Module { - return n.addr.Module -} - -func (n *graphNodeProxyProvider) Name() string { - return n.addr.String() + " (proxy)" -} - -// find the concrete provider instance -func (n *graphNodeProxyProvider) Target() GraphNodeProvider { - switch t := n.target.(type) { - case *graphNodeProxyProvider: - return t.Target() - default: - return n.target - } -} - -// ProviderConfigTransformer adds all provider nodes from the configuration and -// attaches the configs. -type ProviderConfigTransformer struct { - Concrete ConcreteProviderNodeFunc - - // each provider node is stored here so that the proxy nodes can look up - // their targets by name. - providers map[string]GraphNodeProvider - // record providers that can be overriden with a proxy - proxiable map[string]bool - - // Config is the root node of the configuration tree to add providers from. - Config *configs.Config -} - -func (t *ProviderConfigTransformer) Transform(g *Graph) error { - // If no configuration is given, we don't do anything - if t.Config == nil { - return nil - } - - t.providers = make(map[string]GraphNodeProvider) - t.proxiable = make(map[string]bool) - - // Start the transformation process - if err := t.transform(g, t.Config); err != nil { - return err - } - - // finally attach the configs to the new nodes - return t.attachProviderConfigs(g) -} - -func (t *ProviderConfigTransformer) transform(g *Graph, c *configs.Config) error { - // If no config, do nothing - if c == nil { - return nil - } - - // Add our resources - if err := t.transformSingle(g, c); err != nil { - return err - } - - // Transform all the children. - for _, cc := range c.Children { - if err := t.transform(g, cc); err != nil { - return err - } - } - return nil -} - -func (t *ProviderConfigTransformer) transformSingle(g *Graph, c *configs.Config) error { - // Get the module associated with this configuration tree node - mod := c.Module - path := c.Path - - // If this is the root module, we can add nodes for required providers that - // have no configuration, equivalent to having an empty configuration - // block. This will ensure that a provider node exists for modules to - // access when passing around configuration and inheritance. - if path.IsRoot() && c.Module.ProviderRequirements != nil { - for name, p := range c.Module.ProviderRequirements.RequiredProviders { - if _, configured := mod.ProviderConfigs[name]; configured { - continue - } - - addr := addrs.AbsProviderConfig{ - Provider: p.Type, - Module: path, - } - - if _, ok := t.providers[addr.String()]; ok { - // The config validation warns about this too, but we can't - // completely prevent it in v1. - log.Printf("[WARN] ProviderConfigTransformer: duplicate required_providers entry for %s", addr) - continue - } - - abstract := &NodeAbstractProvider{ - Addr: addr, - } - - var v dag.Vertex - if t.Concrete != nil { - v = t.Concrete(abstract) - } else { - v = abstract - } - - g.Add(v) - t.providers[addr.String()] = v.(GraphNodeProvider) - } - } - - // add all providers from the configuration - for _, p := range mod.ProviderConfigs { - fqn := mod.ProviderForLocalConfig(p.Addr()) - addr := addrs.AbsProviderConfig{ - Provider: fqn, - Alias: p.Alias, - Module: path, - } - - if _, ok := t.providers[addr.String()]; ok { - // The abstract provider node may already have been added from the - // provider requirements. - log.Printf("[WARN] ProviderConfigTransformer: provider node %s already added", addr) - continue - } - - abstract := &NodeAbstractProvider{ - Addr: addr, - } - var v dag.Vertex - if t.Concrete != nil { - v = t.Concrete(abstract) - } else { - v = abstract - } - - // Add it to the graph - g.Add(v) - key := addr.String() - t.providers[key] = v.(GraphNodeProvider) - - // While deprecated, we still accept empty configuration blocks within - // modules as being a possible proxy for passed configuration. - if !path.IsRoot() { - // A provider configuration is "proxyable" if its configuration is - // entirely empty. This means it's standing in for a provider - // configuration that must be passed in from the parent module. - // We decide this by evaluating the config with an empty schema; - // if this succeeds, then we know there's nothing in the body. - _, diags := p.Config.Content(&hcl.BodySchema{}) - t.proxiable[key] = !diags.HasErrors() - } - } - - // Now replace the provider nodes with proxy nodes if a provider was being - // passed in, and create implicit proxies if there was no config. Any extra - // proxies will be removed in the prune step. - return t.addProxyProviders(g, c) -} - -func (t *ProviderConfigTransformer) addProxyProviders(g *Graph, c *configs.Config) error { - path := c.Path - - // can't add proxies at the root - if path.IsRoot() { - return nil - } - - parentPath, callAddr := path.Call() - parent := c.Parent - if parent == nil { - return nil - } - - callName := callAddr.Name - var parentCfg *configs.ModuleCall - for name, mod := range parent.Module.ModuleCalls { - if name == callName { - parentCfg = mod - break - } - } - - if parentCfg == nil { - // this can't really happen during normal execution. - return fmt.Errorf("parent module config not found for %s", c.Path.String()) - } - - // Go through all the providers the parent is passing in, and add proxies to - // the parent provider nodes. - for _, pair := range parentCfg.Providers { - fqn := c.Module.ProviderForLocalConfig(pair.InChild.Addr()) - fullAddr := addrs.AbsProviderConfig{ - Provider: fqn, - Module: path, - Alias: pair.InChild.Addr().Alias, - } - - fullParentAddr := addrs.AbsProviderConfig{ - Provider: fqn, - Module: parentPath, - Alias: pair.InParent.Addr().Alias, - } - - fullName := fullAddr.String() - fullParentName := fullParentAddr.String() - - parentProvider := t.providers[fullParentName] - - if parentProvider == nil { - return fmt.Errorf("missing provider %s", fullParentName) - } - - proxy := &graphNodeProxyProvider{ - addr: fullAddr, - target: parentProvider, - } - - concreteProvider := t.providers[fullName] - - // replace the concrete node with the provider passed in only if it is - // proxyable - if concreteProvider != nil { - if t.proxiable[fullName] { - g.Replace(concreteProvider, proxy) - t.providers[fullName] = proxy - } - continue - } - - // There was no concrete provider, so add this as an implicit provider. - // The extra proxy will be pruned later if it's unused. - g.Add(proxy) - t.providers[fullName] = proxy - } - - return nil -} - -func (t *ProviderConfigTransformer) attachProviderConfigs(g *Graph) error { - for _, v := range g.Vertices() { - // Only care about GraphNodeAttachProvider implementations - apn, ok := v.(GraphNodeAttachProvider) - if !ok { - continue - } - - // Determine what we're looking for - addr := apn.ProviderAddr() - - // Get the configuration. - mc := t.Config.Descendent(addr.Module) - if mc == nil { - log.Printf("[TRACE] ProviderConfigTransformer: no configuration available for %s", addr.String()) - continue - } - - // Find the localName for the provider fqn - localName := mc.Module.LocalNameForProvider(addr.Provider) - - // Go through the provider configs to find the matching config - for _, p := range mc.Module.ProviderConfigs { - if p.Name == localName && p.Alias == addr.Alias { - log.Printf("[TRACE] ProviderConfigTransformer: attaching to %q provider configuration from %s", dag.VertexName(v), p.DeclRange) - apn.AttachProvider(p) - break - } - } - } - - return nil -} diff --git a/internal/terraform/transform_provider_test.go b/internal/terraform/transform_provider_test.go deleted file mode 100644 index ff21685710d1..000000000000 --- a/internal/terraform/transform_provider_test.go +++ /dev/null @@ -1,491 +0,0 @@ -package terraform - -import ( - "fmt" - "strings" - "testing" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/dag" -) - -func testProviderTransformerGraph(t *testing.T, cfg *configs.Config) *Graph { - t.Helper() - - g := &Graph{Path: addrs.RootModuleInstance} - ct := &ConfigTransformer{Config: cfg} - if err := ct.Transform(g); err != nil { - t.Fatal(err) - } - arct := &AttachResourceConfigTransformer{Config: cfg} - if err := arct.Transform(g); err != nil { - t.Fatal(err) - } - - return g -} - -func TestProviderTransformer(t *testing.T) { - mod := testModule(t, "transform-provider-basic") - - g := testProviderTransformerGraph(t, mod) - { - transform := &MissingProviderTransformer{} - if err := transform.Transform(g); err != nil { - t.Fatalf("err: %s", err) - } - } - - transform := &ProviderTransformer{} - if err := transform.Transform(g); err != nil { - t.Fatalf("err: %s", err) - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(testTransformProviderBasicStr) - if actual != expected { - t.Fatalf("bad:\n\n%s", actual) - } -} - -// Test providers with FQNs that do not match the typeName -func TestProviderTransformer_fqns(t *testing.T) { - for _, mod := range []string{"fqns", "fqns-module"} { - mod := testModule(t, fmt.Sprintf("transform-provider-%s", mod)) - - g := testProviderTransformerGraph(t, mod) - { - transform := &MissingProviderTransformer{Config: mod} - if err := transform.Transform(g); err != nil { - t.Fatalf("err: %s", err) - } - } - - transform := &ProviderTransformer{Config: mod} - if err := transform.Transform(g); err != nil { - t.Fatalf("err: %s", err) - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(testTransformProviderBasicStr) - if actual != expected { - t.Fatalf("bad:\n\n%s", actual) - } - } -} - -func TestCloseProviderTransformer(t *testing.T) { - mod := testModule(t, "transform-provider-basic") - g := testProviderTransformerGraph(t, mod) - - { - transform := &MissingProviderTransformer{} - if err := transform.Transform(g); err != nil { - t.Fatalf("err: %s", err) - } - } - - { - transform := &ProviderTransformer{} - if err := transform.Transform(g); err != nil { - t.Fatalf("err: %s", err) - } - } - - { - transform := &CloseProviderTransformer{} - if err := transform.Transform(g); err != nil { - t.Fatalf("err: %s", err) - } - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(testTransformCloseProviderBasicStr) - if actual != expected { - t.Fatalf("bad:\n\n%s", actual) - } -} - -func TestCloseProviderTransformer_withTargets(t *testing.T) { - mod := testModule(t, "transform-provider-basic") - - g := testProviderTransformerGraph(t, mod) - transforms := []GraphTransformer{ - &MissingProviderTransformer{}, - &ProviderTransformer{}, - &CloseProviderTransformer{}, - &TargetsTransformer{ - Targets: []addrs.Targetable{ - addrs.RootModuleInstance.Resource( - addrs.ManagedResourceMode, "something", "else", - ), - }, - }, - } - - for _, tr := range transforms { - if err := tr.Transform(g); err != nil { - t.Fatalf("err: %s", err) - } - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(``) - if actual != expected { - t.Fatalf("expected:%s\n\ngot:\n\n%s", expected, actual) - } -} - -func TestMissingProviderTransformer(t *testing.T) { - mod := testModule(t, "transform-provider-missing") - - g := testProviderTransformerGraph(t, mod) - { - transform := &MissingProviderTransformer{} - if err := transform.Transform(g); err != nil { - t.Fatalf("err: %s", err) - } - } - - { - transform := &ProviderTransformer{} - if err := transform.Transform(g); err != nil { - t.Fatalf("err: %s", err) - } - } - - { - transform := &CloseProviderTransformer{} - if err := transform.Transform(g); err != nil { - t.Fatalf("err: %s", err) - } - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(testTransformMissingProviderBasicStr) - if actual != expected { - t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) - } -} - -func TestMissingProviderTransformer_grandchildMissing(t *testing.T) { - mod := testModule(t, "transform-provider-missing-grandchild") - - concrete := func(a *NodeAbstractProvider) dag.Vertex { return a } - - g := testProviderTransformerGraph(t, mod) - { - transform := transformProviders(concrete, mod) - if err := transform.Transform(g); err != nil { - t.Fatalf("err: %s", err) - } - } - { - transform := &TransitiveReductionTransformer{} - if err := transform.Transform(g); err != nil { - t.Fatalf("err: %s", err) - } - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(testTransformMissingGrandchildProviderStr) - if actual != expected { - t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) - } -} - -func TestPruneProviderTransformer(t *testing.T) { - mod := testModule(t, "transform-provider-prune") - - g := testProviderTransformerGraph(t, mod) - { - transform := &MissingProviderTransformer{} - if err := transform.Transform(g); err != nil { - t.Fatalf("err: %s", err) - } - } - - { - transform := &ProviderTransformer{} - if err := transform.Transform(g); err != nil { - t.Fatalf("err: %s", err) - } - } - - { - transform := &CloseProviderTransformer{} - if err := transform.Transform(g); err != nil { - t.Fatalf("err: %s", err) - } - } - - { - transform := &PruneProviderTransformer{} - if err := transform.Transform(g); err != nil { - t.Fatalf("err: %s", err) - } - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(testTransformPruneProviderBasicStr) - if actual != expected { - t.Fatalf("bad:\n\n%s", actual) - } -} - -// the child module resource is attached to the configured parent provider -func TestProviderConfigTransformer_parentProviders(t *testing.T) { - mod := testModule(t, "transform-provider-inherit") - concrete := func(a *NodeAbstractProvider) dag.Vertex { return a } - - g := testProviderTransformerGraph(t, mod) - { - tf := transformProviders(concrete, mod) - if err := tf.Transform(g); err != nil { - t.Fatalf("err: %s", err) - } - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(testTransformModuleProviderConfigStr) - if actual != expected { - t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) - } -} - -// the child module resource is attached to the configured grand-parent provider -func TestProviderConfigTransformer_grandparentProviders(t *testing.T) { - mod := testModule(t, "transform-provider-grandchild-inherit") - concrete := func(a *NodeAbstractProvider) dag.Vertex { return a } - - g := testProviderTransformerGraph(t, mod) - { - tf := transformProviders(concrete, mod) - if err := tf.Transform(g); err != nil { - t.Fatalf("err: %s", err) - } - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(testTransformModuleProviderGrandparentStr) - if actual != expected { - t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) - } -} - -func TestProviderConfigTransformer_inheritOldSkool(t *testing.T) { - mod := testModuleInline(t, map[string]string{ - "main.tf": ` -provider "test" { - test_string = "config" -} - -module "moda" { - source = "./moda" -} -`, - - "moda/main.tf": ` -resource "test_object" "a" { -} -`, - }) - concrete := func(a *NodeAbstractProvider) dag.Vertex { return a } - - g := testProviderTransformerGraph(t, mod) - { - tf := transformProviders(concrete, mod) - if err := tf.Transform(g); err != nil { - t.Fatalf("err: %s", err) - } - } - - expected := `module.moda.test_object.a - provider["registry.terraform.io/hashicorp/test"] -provider["registry.terraform.io/hashicorp/test"]` - - actual := strings.TrimSpace(g.String()) - if actual != expected { - t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) - } -} - -// Verify that configurations which are not recommended yet supported still work -func TestProviderConfigTransformer_nestedModuleProviders(t *testing.T) { - mod := testModuleInline(t, map[string]string{ - "main.tf": ` -terraform { - required_providers { - test = { - source = "registry.terraform.io/hashicorp/test" - } - } -} - -provider "test" { - alias = "z" - test_string = "config" -} - -module "moda" { - source = "./moda" - providers = { - test.x = test.z - } -} -`, - - "moda/main.tf": ` -terraform { - required_providers { - test = { - source = "registry.terraform.io/hashicorp/test" - configuration_aliases = [ test.x ] - } - } -} - -provider "test" { - test_string = "config" -} - -// this should connect to this module's provider -resource "test_object" "a" { -} - -resource "test_object" "x" { - provider = test.x -} - -module "modb" { - source = "./modb" -} -`, - - "moda/modb/main.tf": ` -# this should end up with the provider from the parent module -resource "test_object" "a" { -} -`, - }) - concrete := func(a *NodeAbstractProvider) dag.Vertex { return a } - - g := testProviderTransformerGraph(t, mod) - { - tf := transformProviders(concrete, mod) - if err := tf.Transform(g); err != nil { - t.Fatalf("err: %s", err) - } - } - - expected := `module.moda.module.modb.test_object.a - module.moda.provider["registry.terraform.io/hashicorp/test"] -module.moda.provider["registry.terraform.io/hashicorp/test"] -module.moda.test_object.a - module.moda.provider["registry.terraform.io/hashicorp/test"] -module.moda.test_object.x - provider["registry.terraform.io/hashicorp/test"].z -provider["registry.terraform.io/hashicorp/test"].z` - - actual := strings.TrimSpace(g.String()) - if actual != expected { - t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) - } -} - -func TestProviderConfigTransformer_duplicateLocalName(t *testing.T) { - mod := testModuleInline(t, map[string]string{ - "main.tf": ` -terraform { - required_providers { - # We have to allow this since it wasn't previously prevented. If the - # default config is equivalent to the provider config, the user may never - # see an error. - dupe = { - source = "registry.terraform.io/hashicorp/test" - } - } -} - -provider "test" { -} -`}) - concrete := func(a *NodeAbstractProvider) dag.Vertex { return a } - - g := testProviderTransformerGraph(t, mod) - tf := ProviderConfigTransformer{ - Config: mod, - Concrete: concrete, - } - if err := tf.Transform(g); err != nil { - t.Fatalf("err: %s", err) - } - - expected := `provider["registry.terraform.io/hashicorp/test"]` - - actual := strings.TrimSpace(g.String()) - if actual != expected { - t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) - } -} - -const testTransformProviderBasicStr = ` -aws_instance.web - provider["registry.terraform.io/hashicorp/aws"] -provider["registry.terraform.io/hashicorp/aws"] -` - -const testTransformCloseProviderBasicStr = ` -aws_instance.web - provider["registry.terraform.io/hashicorp/aws"] -provider["registry.terraform.io/hashicorp/aws"] -provider["registry.terraform.io/hashicorp/aws"] (close) - aws_instance.web - provider["registry.terraform.io/hashicorp/aws"] -` - -const testTransformMissingProviderBasicStr = ` -aws_instance.web - provider["registry.terraform.io/hashicorp/aws"] -foo_instance.web - provider["registry.terraform.io/hashicorp/foo"] -provider["registry.terraform.io/hashicorp/aws"] -provider["registry.terraform.io/hashicorp/aws"] (close) - aws_instance.web - provider["registry.terraform.io/hashicorp/aws"] -provider["registry.terraform.io/hashicorp/foo"] -provider["registry.terraform.io/hashicorp/foo"] (close) - foo_instance.web - provider["registry.terraform.io/hashicorp/foo"] -` - -const testTransformMissingGrandchildProviderStr = ` -module.sub.module.subsub.bar_instance.two - provider["registry.terraform.io/hashicorp/bar"] -module.sub.module.subsub.foo_instance.one - module.sub.provider["registry.terraform.io/hashicorp/foo"] -module.sub.provider["registry.terraform.io/hashicorp/foo"] -provider["registry.terraform.io/hashicorp/bar"] -` - -const testTransformPruneProviderBasicStr = ` -foo_instance.web - provider["registry.terraform.io/hashicorp/foo"] -provider["registry.terraform.io/hashicorp/foo"] -provider["registry.terraform.io/hashicorp/foo"] (close) - foo_instance.web - provider["registry.terraform.io/hashicorp/foo"] -` - -const testTransformModuleProviderConfigStr = ` -module.child.aws_instance.thing - provider["registry.terraform.io/hashicorp/aws"].foo -provider["registry.terraform.io/hashicorp/aws"].foo -` - -const testTransformModuleProviderGrandparentStr = ` -module.child.module.grandchild.aws_instance.baz - provider["registry.terraform.io/hashicorp/aws"].foo -provider["registry.terraform.io/hashicorp/aws"].foo -` diff --git a/internal/terraform/transform_provisioner.go b/internal/terraform/transform_provisioner.go deleted file mode 100644 index 38e3a8ed714e..000000000000 --- a/internal/terraform/transform_provisioner.go +++ /dev/null @@ -1,8 +0,0 @@ -package terraform - -// GraphNodeProvisionerConsumer is an interface that nodes that require -// a provisioner must implement. ProvisionedBy must return the names of the -// provisioners to use. -type GraphNodeProvisionerConsumer interface { - ProvisionedBy() []string -} diff --git a/internal/terraform/transform_reference.go b/internal/terraform/transform_reference.go deleted file mode 100644 index fb8feb2f2a7f..000000000000 --- a/internal/terraform/transform_reference.go +++ /dev/null @@ -1,557 +0,0 @@ -package terraform - -import ( - "fmt" - "log" - "sort" - - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/dag" - "github.com/hashicorp/terraform/internal/lang" -) - -// GraphNodeReferenceable must be implemented by any node that represents -// a Terraform thing that can be referenced (resource, module, etc.). -// -// Even if the thing has no name, this should return an empty list. By -// implementing this and returning a non-nil result, you say that this CAN -// be referenced and other methods of referencing may still be possible (such -// as by path!) -type GraphNodeReferenceable interface { - GraphNodeModulePath - - // ReferenceableAddrs returns a list of addresses through which this can be - // referenced. - ReferenceableAddrs() []addrs.Referenceable -} - -// GraphNodeReferencer must be implemented by nodes that reference other -// Terraform items and therefore depend on them. -type GraphNodeReferencer interface { - GraphNodeModulePath - - // References returns a list of references made by this node, which - // include both a referenced address and source location information for - // the reference. - References() []*addrs.Reference -} - -type GraphNodeAttachDependencies interface { - GraphNodeConfigResource - AttachDependencies([]addrs.ConfigResource) -} - -// graphNodeDependsOn is implemented by resources that need to expose any -// references set via DependsOn in their configuration. -type graphNodeDependsOn interface { - GraphNodeReferencer - DependsOn() []*addrs.Reference -} - -// graphNodeAttachDataResourceDependsOn records all resources that are transitively -// referenced through depends_on in the configuration. This is used by data -// resources to determine if they can be read during the plan, or if they need -// to be further delayed until apply. -// We can only use an addrs.ConfigResource address here, because modules are -// not yet expended in the graph. While this will cause some extra data -// resources to show in the plan when their depends_on references may be in -// unrelated module instances, the fact that it only happens when there are any -// resource updates pending means we can still avoid the problem of the -// "perpetual diff" -type graphNodeAttachDataResourceDependsOn interface { - GraphNodeConfigResource - graphNodeDependsOn - - // AttachDataResourceDependsOn stores the discovered dependencies in the - // resource node for evaluation later. - // - // The force parameter indicates that even if there are no dependencies, - // force the data source to act as though there are for refresh purposes. - // This is needed because yet-to-be-created resources won't be in the - // initial refresh graph, but may still be referenced through depends_on. - AttachDataResourceDependsOn(deps []addrs.ConfigResource, force bool) -} - -// GraphNodeReferenceOutside is an interface that can optionally be implemented. -// A node that implements it can specify that its own referenceable addresses -// and/or the addresses it references are in a different module than the -// node itself. -// -// Any referenceable addresses returned by ReferenceableAddrs are interpreted -// relative to the returned selfPath. -// -// Any references returned by References are interpreted relative to the -// returned referencePath. -// -// It is valid but not required for either of these paths to match what is -// returned by method Path, though if both match the main Path then there -// is no reason to implement this method. -// -// The primary use-case for this is the nodes representing module input -// variables, since their expressions are resolved in terms of their calling -// module, but they are still referenced from their own module. -type GraphNodeReferenceOutside interface { - // ReferenceOutside returns a path in which any references from this node - // are resolved. - ReferenceOutside() (selfPath, referencePath addrs.Module) -} - -// ReferenceTransformer is a GraphTransformer that connects all the -// nodes that reference each other in order to form the proper ordering. -type ReferenceTransformer struct{} - -func (t *ReferenceTransformer) Transform(g *Graph) error { - // Build a reference map so we can efficiently look up the references - vs := g.Vertices() - m := NewReferenceMap(vs) - - // Find the things that reference things and connect them - for _, v := range vs { - if _, ok := v.(GraphNodeDestroyer); ok { - // destroy nodes references are not connected, since they can only - // use their own state. - continue - } - - parents := m.References(v) - parentsDbg := make([]string, len(parents)) - for i, v := range parents { - parentsDbg[i] = dag.VertexName(v) - } - log.Printf( - "[DEBUG] ReferenceTransformer: %q references: %v", - dag.VertexName(v), parentsDbg) - - for _, parent := range parents { - // A destroy plan relies solely on the state, so we only need to - // ensure that temporary values are connected to get the evaluation - // order correct. Any references to destroy nodes will cause - // cycles, because they are connected in reverse order. - if _, ok := parent.(GraphNodeDestroyer); ok { - continue - } - - if !graphNodesAreResourceInstancesInDifferentInstancesOfSameModule(v, parent) { - g.Connect(dag.BasicEdge(v, parent)) - } else { - log.Printf("[TRACE] ReferenceTransformer: skipping %s => %s inter-module-instance dependency", dag.VertexName(v), dag.VertexName(parent)) - } - } - - if len(parents) > 0 { - continue - } - } - - return nil -} - -type depMap map[string]addrs.ConfigResource - -// add stores the vertex if it represents a resource in the -// graph. -func (m depMap) add(v dag.Vertex) { - // we're only concerned with resources which may have changes that - // need to be applied. - switch v := v.(type) { - case GraphNodeResourceInstance: - instAddr := v.ResourceInstanceAddr() - addr := instAddr.ContainingResource().Config() - m[addr.String()] = addr - case GraphNodeConfigResource: - addr := v.ResourceAddr() - m[addr.String()] = addr - } -} - -// attachDataResourceDependsOnTransformer records all resources transitively -// referenced through a configuration depends_on. -type attachDataResourceDependsOnTransformer struct { -} - -func (t attachDataResourceDependsOnTransformer) Transform(g *Graph) error { - // First we need to make a map of referenceable addresses to their vertices. - // This is very similar to what's done in ReferenceTransformer, but we keep - // implementation separate as they may need to change independently. - vertices := g.Vertices() - refMap := NewReferenceMap(vertices) - - for _, v := range vertices { - depender, ok := v.(graphNodeAttachDataResourceDependsOn) - if !ok { - continue - } - - // Only data need to attach depends_on, so they can determine if they - // are eligible to be read during plan. - if depender.ResourceAddr().Resource.Mode != addrs.DataResourceMode { - continue - } - - // depMap will only add resource references then dedupe - deps := make(depMap) - dependsOnDeps, fromModule := refMap.dependsOn(g, depender) - for _, dep := range dependsOnDeps { - // any the dependency - deps.add(dep) - } - - res := make([]addrs.ConfigResource, 0, len(deps)) - for _, d := range deps { - res = append(res, d) - } - - log.Printf("[TRACE] attachDataDependenciesTransformer: %s depends on %s", depender.ResourceAddr(), res) - depender.AttachDataResourceDependsOn(res, fromModule) - } - - return nil -} - -// AttachDependenciesTransformer records all resource dependencies for each -// instance, and attaches the addresses to the node itself. Managed resource -// will record these in the state for proper ordering of destroy operations. -type AttachDependenciesTransformer struct { -} - -func (t AttachDependenciesTransformer) Transform(g *Graph) error { - for _, v := range g.Vertices() { - attacher, ok := v.(GraphNodeAttachDependencies) - if !ok { - continue - } - selfAddr := attacher.ResourceAddr() - - ans, err := g.Ancestors(v) - if err != nil { - return err - } - - // dedupe addrs when there's multiple instances involved, or - // multiple paths in the un-reduced graph - depMap := map[string]addrs.ConfigResource{} - for _, d := range ans { - var addr addrs.ConfigResource - - switch d := d.(type) { - case GraphNodeResourceInstance: - instAddr := d.ResourceInstanceAddr() - addr = instAddr.ContainingResource().Config() - case GraphNodeConfigResource: - addr = d.ResourceAddr() - default: - continue - } - - if addr.Equal(selfAddr) { - continue - } - depMap[addr.String()] = addr - } - - deps := make([]addrs.ConfigResource, 0, len(depMap)) - for _, d := range depMap { - deps = append(deps, d) - } - sort.Slice(deps, func(i, j int) bool { - return deps[i].String() < deps[j].String() - }) - - log.Printf("[TRACE] AttachDependenciesTransformer: %s depends on %s", attacher.ResourceAddr(), deps) - attacher.AttachDependencies(deps) - } - - return nil -} - -func isDependableResource(v dag.Vertex) bool { - switch v.(type) { - case GraphNodeResourceInstance: - return true - case GraphNodeConfigResource: - return true - } - return false -} - -// ReferenceMap is a structure that can be used to efficiently check -// for references on a graph, mapping internal reference keys (as produced by -// the mapKey method) to one or more vertices that are identified by each key. -type ReferenceMap map[string][]dag.Vertex - -// References returns the set of vertices that the given vertex refers to, -// and any referenced addresses that do not have corresponding vertices. -func (m ReferenceMap) References(v dag.Vertex) []dag.Vertex { - rn, ok := v.(GraphNodeReferencer) - if !ok { - return nil - } - - var matches []dag.Vertex - - for _, ref := range rn.References() { - subject := ref.Subject - - key := m.referenceMapKey(v, subject) - if _, exists := m[key]; !exists { - // If what we were looking for was a ResourceInstance then we - // might be in a resource-oriented graph rather than an - // instance-oriented graph, and so we'll see if we have the - // resource itself instead. - switch ri := subject.(type) { - case addrs.ResourceInstance: - subject = ri.ContainingResource() - case addrs.ResourceInstancePhase: - subject = ri.ContainingResource() - case addrs.ModuleCallInstanceOutput: - subject = ri.ModuleCallOutput() - case addrs.ModuleCallInstance: - subject = ri.Call - default: - log.Printf("[INFO] ReferenceTransformer: reference not found: %q", subject) - continue - } - key = m.referenceMapKey(v, subject) - } - vertices := m[key] - for _, rv := range vertices { - // don't include self-references - if rv == v { - continue - } - matches = append(matches, rv) - } - } - - return matches -} - -// dependsOn returns the set of vertices that the given vertex refers to from -// the configured depends_on. The bool return value indicates if depends_on was -// found in a parent module configuration. -func (m ReferenceMap) dependsOn(g *Graph, depender graphNodeDependsOn) ([]dag.Vertex, bool) { - var res []dag.Vertex - fromModule := false - - refs := depender.DependsOn() - - // get any implied dependencies for data sources - refs = append(refs, m.dataDependsOn(depender)...) - - // This is where we record that a module has depends_on configured. - if _, ok := depender.(*nodeExpandModule); ok && len(refs) > 0 { - fromModule = true - } - - for _, ref := range refs { - subject := ref.Subject - - key := m.referenceMapKey(depender, subject) - vertices, ok := m[key] - if !ok { - // the ReferenceMap generates all possible keys, so any warning - // here is probably not useful for this implementation. - continue - } - for _, rv := range vertices { - // don't include self-references - if rv == depender { - continue - } - res = append(res, rv) - - // Check any ancestors for transitive dependencies when we're - // not pointed directly at a resource. We can't be much more - // precise here, since in order to maintain our guarantee that data - // sources will wait for explicit dependencies, if those dependencies - // happen to be a module, output, or variable, we have to find some - // upstream managed resource in order to check for a planned - // change. - if _, ok := rv.(GraphNodeConfigResource); !ok { - ans, _ := g.Ancestors(rv) - for _, v := range ans { - if isDependableResource(v) { - res = append(res, v) - } - } - } - } - } - - parentDeps, fromParentModule := m.parentModuleDependsOn(g, depender) - res = append(res, parentDeps...) - - return res, fromModule || fromParentModule -} - -// Return extra depends_on references if this is a data source. -// For data sources we implicitly treat references to managed resources as -// depends_on entries. If a data source references a managed resource, even if -// that reference is resolvable, it stands to reason that the user intends for -// the data source to require that resource in some way. -func (m ReferenceMap) dataDependsOn(depender graphNodeDependsOn) []*addrs.Reference { - var refs []*addrs.Reference - if n, ok := depender.(GraphNodeConfigResource); ok && - n.ResourceAddr().Resource.Mode == addrs.DataResourceMode { - for _, r := range depender.References() { - - var resAddr addrs.Resource - switch s := r.Subject.(type) { - case addrs.Resource: - resAddr = s - case addrs.ResourceInstance: - resAddr = s.Resource - r.Subject = resAddr - } - - if resAddr.Mode != addrs.ManagedResourceMode { - // We only want to wait on directly referenced managed resources. - // Data sources have no external side effects, so normal - // references to them in the config will suffice for proper - // ordering. - continue - } - - refs = append(refs, r) - } - } - return refs -} - -// parentModuleDependsOn returns the set of vertices that a data sources parent -// module references through the module call's depends_on. The bool return -// value indicates if depends_on was found in a parent module configuration. -func (m ReferenceMap) parentModuleDependsOn(g *Graph, depender graphNodeDependsOn) ([]dag.Vertex, bool) { - var res []dag.Vertex - fromModule := false - - // Look for containing modules with DependsOn. - // This should be connected directly to the module node, so we only need to - // look one step away. - for _, v := range g.DownEdges(depender) { - // we're only concerned with module expansion nodes here. - mod, ok := v.(*nodeExpandModule) - if !ok { - continue - } - - deps, fromParentModule := m.dependsOn(g, mod) - for _, dep := range deps { - // add the dependency - res = append(res, dep) - - // and check any transitive resource dependencies for more resources - ans, _ := g.Ancestors(dep) - for _, v := range ans { - if isDependableResource(v) { - res = append(res, v) - } - } - } - fromModule = fromModule || fromParentModule - } - - return res, fromModule -} - -func (m *ReferenceMap) mapKey(path addrs.Module, addr addrs.Referenceable) string { - return fmt.Sprintf("%s|%s", path.String(), addr.String()) -} - -// vertexReferenceablePath returns the path in which the given vertex can be -// referenced. This is the path that its results from ReferenceableAddrs -// are considered to be relative to. -// -// Only GraphNodeModulePath implementations can be referenced, so this method will -// panic if the given vertex does not implement that interface. -func vertexReferenceablePath(v dag.Vertex) addrs.Module { - sp, ok := v.(GraphNodeModulePath) - if !ok { - // Only nodes with paths can participate in a reference map. - panic(fmt.Errorf("vertexMapKey on vertex type %T which doesn't implement GraphNodeModulePath", sp)) - } - - if outside, ok := v.(GraphNodeReferenceOutside); ok { - // Vertex is referenced from a different module than where it was - // declared. - path, _ := outside.ReferenceOutside() - return path - } - - // Vertex is referenced from the same module as where it was declared. - return sp.ModulePath() -} - -// vertexReferencePath returns the path in which references _from_ the given -// vertex must be interpreted. -// -// Only GraphNodeModulePath implementations can have references, so this method -// will panic if the given vertex does not implement that interface. -func vertexReferencePath(v dag.Vertex) addrs.Module { - sp, ok := v.(GraphNodeModulePath) - if !ok { - // Only nodes with paths can participate in a reference map. - panic(fmt.Errorf("vertexReferencePath on vertex type %T which doesn't implement GraphNodeModulePath", v)) - } - - if outside, ok := v.(GraphNodeReferenceOutside); ok { - // Vertex makes references to objects in a different module than where - // it was declared. - _, path := outside.ReferenceOutside() - return path - } - - // Vertex makes references to objects in the same module as where it - // was declared. - return sp.ModulePath() -} - -// referenceMapKey produces keys for the "edges" map. "referrer" is the vertex -// that the reference is from, and "addr" is the address of the object being -// referenced. -// -// The result is an opaque string that includes both the address of the given -// object and the address of the module instance that object belongs to. -// -// Only GraphNodeModulePath implementations can be referrers, so this method will -// panic if the given vertex does not implement that interface. -func (m *ReferenceMap) referenceMapKey(referrer dag.Vertex, addr addrs.Referenceable) string { - path := vertexReferencePath(referrer) - return m.mapKey(path, addr) -} - -// NewReferenceMap is used to create a new reference map for the -// given set of vertices. -func NewReferenceMap(vs []dag.Vertex) ReferenceMap { - // Build the lookup table - m := make(ReferenceMap) - for _, v := range vs { - // We're only looking for referenceable nodes - rn, ok := v.(GraphNodeReferenceable) - if !ok { - continue - } - - path := vertexReferenceablePath(v) - - // Go through and cache them - for _, addr := range rn.ReferenceableAddrs() { - key := m.mapKey(path, addr) - m[key] = append(m[key], v) - } - } - - return m -} - -// ReferencesFromConfig returns the references that a configuration has -// based on the interpolated variables in a configuration. -func ReferencesFromConfig(body hcl.Body, schema *configschema.Block) []*addrs.Reference { - if body == nil { - return nil - } - refs, _ := lang.ReferencesInBlock(body, schema) - return refs -} diff --git a/internal/terraform/transform_reference_test.go b/internal/terraform/transform_reference_test.go deleted file mode 100644 index 50e47e19b860..000000000000 --- a/internal/terraform/transform_reference_test.go +++ /dev/null @@ -1,319 +0,0 @@ -package terraform - -import ( - "reflect" - "sort" - "strings" - "testing" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/dag" -) - -func TestReferenceTransformer_simple(t *testing.T) { - g := Graph{Path: addrs.RootModuleInstance} - g.Add(&graphNodeRefParentTest{ - NameValue: "A", - Names: []string{"A"}, - }) - g.Add(&graphNodeRefChildTest{ - NameValue: "B", - Refs: []string{"A"}, - }) - - tf := &ReferenceTransformer{} - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(testTransformRefBasicStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestReferenceTransformer_self(t *testing.T) { - g := Graph{Path: addrs.RootModuleInstance} - g.Add(&graphNodeRefParentTest{ - NameValue: "A", - Names: []string{"A"}, - }) - g.Add(&graphNodeRefChildTest{ - NameValue: "B", - Refs: []string{"A", "B"}, - }) - - tf := &ReferenceTransformer{} - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(testTransformRefBasicStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestReferenceTransformer_path(t *testing.T) { - g := Graph{Path: addrs.RootModuleInstance} - g.Add(&graphNodeRefParentTest{ - NameValue: "A", - Names: []string{"A"}, - }) - g.Add(&graphNodeRefChildTest{ - NameValue: "B", - Refs: []string{"A"}, - }) - g.Add(&graphNodeRefParentTest{ - NameValue: "child.A", - PathValue: addrs.ModuleInstance{addrs.ModuleInstanceStep{Name: "child"}}, - Names: []string{"A"}, - }) - g.Add(&graphNodeRefChildTest{ - NameValue: "child.B", - PathValue: addrs.ModuleInstance{addrs.ModuleInstanceStep{Name: "child"}}, - Refs: []string{"A"}, - }) - - tf := &ReferenceTransformer{} - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(testTransformRefPathStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestReferenceTransformer_resourceInstances(t *testing.T) { - // Our reference analyses are all done based on unexpanded addresses - // so that we can use this transformer both in the plan graph (where things - // are not expanded yet) and the apply graph (where resource instances are - // pre-expanded but nothing else is.) - // However, that would make the result too conservative about instances - // of the same resource in different instances of the same module, so we - // make an exception for that situation in particular, keeping references - // between resource instances segregated by their containing module - // instance. - g := Graph{Path: addrs.RootModuleInstance} - moduleInsts := []addrs.ModuleInstance{ - { - { - Name: "foo", InstanceKey: addrs.IntKey(0), - }, - }, - { - { - Name: "foo", InstanceKey: addrs.IntKey(1), - }, - }, - } - resourceAs := make([]addrs.AbsResourceInstance, len(moduleInsts)) - for i, moduleInst := range moduleInsts { - resourceAs[i] = addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "thing", - Name: "a", - }.Instance(addrs.NoKey).Absolute(moduleInst) - } - resourceBs := make([]addrs.AbsResourceInstance, len(moduleInsts)) - for i, moduleInst := range moduleInsts { - resourceBs[i] = addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "thing", - Name: "b", - }.Instance(addrs.NoKey).Absolute(moduleInst) - } - g.Add(&graphNodeFakeResourceInstance{ - Addr: resourceAs[0], - }) - g.Add(&graphNodeFakeResourceInstance{ - Addr: resourceBs[0], - Refs: []*addrs.Reference{ - { - Subject: resourceAs[0].Resource, - }, - }, - }) - g.Add(&graphNodeFakeResourceInstance{ - Addr: resourceAs[1], - }) - g.Add(&graphNodeFakeResourceInstance{ - Addr: resourceBs[1], - Refs: []*addrs.Reference{ - { - Subject: resourceAs[1].Resource, - }, - }, - }) - - tf := &ReferenceTransformer{} - if err := tf.Transform(&g); err != nil { - t.Fatalf("unexpected error: %s", err) - } - - // Resource B should be connected to resource A in each module instance, - // but there should be no connections between the two module instances. - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(` -module.foo[0].thing.a -module.foo[0].thing.b - module.foo[0].thing.a -module.foo[1].thing.a -module.foo[1].thing.b - module.foo[1].thing.a -`) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -func TestReferenceMapReferences(t *testing.T) { - cases := map[string]struct { - Nodes []dag.Vertex - Check dag.Vertex - Result []string - }{ - "simple": { - Nodes: []dag.Vertex{ - &graphNodeRefParentTest{ - NameValue: "A", - Names: []string{"A"}, - }, - }, - Check: &graphNodeRefChildTest{ - NameValue: "foo", - Refs: []string{"A"}, - }, - Result: []string{"A"}, - }, - } - - for tn, tc := range cases { - t.Run(tn, func(t *testing.T) { - rm := NewReferenceMap(tc.Nodes) - result := rm.References(tc.Check) - - var resultStr []string - for _, v := range result { - resultStr = append(resultStr, dag.VertexName(v)) - } - - sort.Strings(resultStr) - sort.Strings(tc.Result) - if !reflect.DeepEqual(resultStr, tc.Result) { - t.Fatalf("bad: %#v", resultStr) - } - }) - } -} - -type graphNodeRefParentTest struct { - NameValue string - PathValue addrs.ModuleInstance - Names []string -} - -var _ GraphNodeReferenceable = (*graphNodeRefParentTest)(nil) - -func (n *graphNodeRefParentTest) Name() string { - return n.NameValue -} - -func (n *graphNodeRefParentTest) ReferenceableAddrs() []addrs.Referenceable { - ret := make([]addrs.Referenceable, len(n.Names)) - for i, name := range n.Names { - ret[i] = addrs.LocalValue{Name: name} - } - return ret -} - -func (n *graphNodeRefParentTest) Path() addrs.ModuleInstance { - return n.PathValue -} - -func (n *graphNodeRefParentTest) ModulePath() addrs.Module { - return n.PathValue.Module() -} - -type graphNodeRefChildTest struct { - NameValue string - PathValue addrs.ModuleInstance - Refs []string -} - -var _ GraphNodeReferencer = (*graphNodeRefChildTest)(nil) - -func (n *graphNodeRefChildTest) Name() string { - return n.NameValue -} - -func (n *graphNodeRefChildTest) References() []*addrs.Reference { - ret := make([]*addrs.Reference, len(n.Refs)) - for i, name := range n.Refs { - ret[i] = &addrs.Reference{ - Subject: addrs.LocalValue{Name: name}, - } - } - return ret -} - -func (n *graphNodeRefChildTest) Path() addrs.ModuleInstance { - return n.PathValue -} - -func (n *graphNodeRefChildTest) ModulePath() addrs.Module { - return n.PathValue.Module() -} - -type graphNodeFakeResourceInstance struct { - Addr addrs.AbsResourceInstance - Refs []*addrs.Reference -} - -var _ GraphNodeResourceInstance = (*graphNodeFakeResourceInstance)(nil) -var _ GraphNodeReferenceable = (*graphNodeFakeResourceInstance)(nil) -var _ GraphNodeReferencer = (*graphNodeFakeResourceInstance)(nil) - -func (n *graphNodeFakeResourceInstance) ResourceInstanceAddr() addrs.AbsResourceInstance { - return n.Addr -} - -func (n *graphNodeFakeResourceInstance) ModulePath() addrs.Module { - return n.Addr.Module.Module() -} - -func (n *graphNodeFakeResourceInstance) ReferenceableAddrs() []addrs.Referenceable { - return []addrs.Referenceable{n.Addr.Resource} -} - -func (n *graphNodeFakeResourceInstance) References() []*addrs.Reference { - return n.Refs -} - -func (n *graphNodeFakeResourceInstance) StateDependencies() []addrs.ConfigResource { - return nil -} - -func (n *graphNodeFakeResourceInstance) String() string { - return n.Addr.String() -} - -const testTransformRefBasicStr = ` -A -B - A -` - -const testTransformRefPathStr = ` -A -B - A -child.A -child.B - child.A -` diff --git a/internal/terraform/transform_removed_modules.go b/internal/terraform/transform_removed_modules.go deleted file mode 100644 index 090582ce2081..000000000000 --- a/internal/terraform/transform_removed_modules.go +++ /dev/null @@ -1,44 +0,0 @@ -package terraform - -import ( - "log" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/states" -) - -// RemovedModuleTransformer implements GraphTransformer to add nodes indicating -// when a module was removed from the configuration. -type RemovedModuleTransformer struct { - Config *configs.Config // root node in the config tree - State *states.State -} - -func (t *RemovedModuleTransformer) Transform(g *Graph) error { - // nothing to remove if there's no state! - if t.State == nil { - return nil - } - - removed := map[string]addrs.Module{} - - for _, m := range t.State.Modules { - cc := t.Config.DescendentForInstance(m.Addr) - if cc != nil { - continue - } - removed[m.Addr.Module().String()] = m.Addr.Module() - log.Printf("[DEBUG] %s is no longer in configuration\n", m.Addr) - } - - // add closers to collect any module instances we're removing - for _, modAddr := range removed { - closer := &nodeCloseModule{ - Addr: modAddr, - } - g.Add(closer) - } - - return nil -} diff --git a/internal/terraform/transform_resource_count.go b/internal/terraform/transform_resource_count.go deleted file mode 100644 index 4d853593eb71..000000000000 --- a/internal/terraform/transform_resource_count.go +++ /dev/null @@ -1,36 +0,0 @@ -package terraform - -import ( - "log" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/dag" -) - -// ResourceCountTransformer is a GraphTransformer that expands the count -// out for a specific resource. -// -// This assumes that the count is already interpolated. -type ResourceCountTransformer struct { - Concrete ConcreteResourceInstanceNodeFunc - Schema *configschema.Block - - Addr addrs.ConfigResource - InstanceAddrs []addrs.AbsResourceInstance -} - -func (t *ResourceCountTransformer) Transform(g *Graph) error { - for _, addr := range t.InstanceAddrs { - abstract := NewNodeAbstractResourceInstance(addr) - abstract.Schema = t.Schema - var node dag.Vertex = abstract - if f := t.Concrete; f != nil { - node = f(abstract) - } - - log.Printf("[TRACE] ResourceCountTransformer: adding %s as %T", addr, node) - g.Add(node) - } - return nil -} diff --git a/internal/terraform/transform_root.go b/internal/terraform/transform_root.go deleted file mode 100644 index e06ef5b414cf..000000000000 --- a/internal/terraform/transform_root.go +++ /dev/null @@ -1,82 +0,0 @@ -package terraform - -import ( - "github.com/hashicorp/terraform/internal/dag" -) - -const rootNodeName = "root" - -// RootTransformer is a GraphTransformer that adds a root to the graph. -type RootTransformer struct{} - -func (t *RootTransformer) Transform(g *Graph) error { - addRootNodeToGraph(g) - return nil -} - -// addRootNodeToGraph modifies the given graph in-place so that it has a root -// node if it didn't already have one and so that any other node which doesn't -// already depend on something will depend on that root node. -// -// After this function returns, the graph will have only one node that doesn't -// depend on any other nodes. -func addRootNodeToGraph(g *Graph) { - // We always add the root node. This is a singleton so if it's already - // in the graph this will do nothing and just retain the existing root node. - // - // Note that rootNode is intentionally added by value and not by pointer - // so that all root nodes will be equal to one another and therefore - // coalesce when two valid graphs get merged together into a single graph. - g.Add(rootNode) - - // Everything that doesn't already depend on at least one other node will - // depend on the root node, except the root node itself. - for _, v := range g.Vertices() { - if v == dag.Vertex(rootNode) { - continue - } - - if g.UpEdges(v).Len() == 0 { - g.Connect(dag.BasicEdge(rootNode, v)) - } - } -} - -type graphNodeRoot struct{} - -// rootNode is the singleton value representing all root graph nodes. -// -// The root node for all graphs should be this value directly, and in particular -// _not_ a pointer to this value. Using the value directly here means that -// multiple root nodes will always coalesce together when subsuming one graph -// into another. -var rootNode graphNodeRoot - -func (n graphNodeRoot) Name() string { - return rootNodeName -} - -// CloseRootModuleTransformer is a GraphTransformer that adds a root to the graph. -type CloseRootModuleTransformer struct{} - -func (t *CloseRootModuleTransformer) Transform(g *Graph) error { - // close the root module - closeRoot := &nodeCloseModule{} - g.Add(closeRoot) - - // since this is closing the root module, make it depend on everything in - // the root module. - for _, v := range g.Vertices() { - if v == closeRoot { - continue - } - - // since this is closing the root module, and must be last, we can - // connect to anything that doesn't have any up edges. - if g.UpEdges(v).Len() == 0 { - g.Connect(dag.BasicEdge(closeRoot, v)) - } - } - - return nil -} diff --git a/internal/terraform/transform_root_test.go b/internal/terraform/transform_root_test.go deleted file mode 100644 index 61f24a5f764a..000000000000 --- a/internal/terraform/transform_root_test.go +++ /dev/null @@ -1,95 +0,0 @@ -package terraform - -import ( - "strings" - "testing" - - "github.com/hashicorp/terraform/internal/addrs" -) - -func TestRootTransformer(t *testing.T) { - t.Run("many nodes", func(t *testing.T) { - mod := testModule(t, "transform-root-basic") - - g := Graph{Path: addrs.RootModuleInstance} - { - tf := &ConfigTransformer{Config: mod} - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - } - - { - transform := &MissingProviderTransformer{} - if err := transform.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - } - - { - transform := &ProviderTransformer{} - if err := transform.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - } - - { - transform := &RootTransformer{} - if err := transform.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(testTransformRootBasicStr) - if actual != expected { - t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) - } - - root, err := g.Root() - if err != nil { - t.Fatalf("err: %s", err) - } - if _, ok := root.(graphNodeRoot); !ok { - t.Fatalf("bad: %#v", root) - } - }) - - t.Run("only one initial node", func(t *testing.T) { - g := Graph{Path: addrs.RootModuleInstance} - g.Add("foo") - addRootNodeToGraph(&g) - got := strings.TrimSpace(g.String()) - want := strings.TrimSpace(` -foo -root - foo -`) - if got != want { - t.Errorf("wrong final graph\ngot:\n%s\nwant:\n%s", got, want) - } - }) - - t.Run("graph initially empty", func(t *testing.T) { - g := Graph{Path: addrs.RootModuleInstance} - addRootNodeToGraph(&g) - got := strings.TrimSpace(g.String()) - want := `root` - if got != want { - t.Errorf("wrong final graph\ngot:\n%s\nwant:\n%s", got, want) - } - }) - -} - -const testTransformRootBasicStr = ` -aws_instance.foo - provider["registry.terraform.io/hashicorp/aws"] -do_droplet.bar - provider["registry.terraform.io/hashicorp/do"] -provider["registry.terraform.io/hashicorp/aws"] -provider["registry.terraform.io/hashicorp/do"] -root - aws_instance.foo - do_droplet.bar -` diff --git a/internal/terraform/transform_state.go b/internal/terraform/transform_state.go deleted file mode 100644 index 1ca060a88aad..000000000000 --- a/internal/terraform/transform_state.go +++ /dev/null @@ -1,72 +0,0 @@ -package terraform - -import ( - "log" - - "github.com/hashicorp/terraform/internal/states" -) - -// StateTransformer is a GraphTransformer that adds the elements of -// the state to the graph. -// -// This transform is used for example by the DestroyPlanGraphBuilder to ensure -// that only resources that are in the state are represented in the graph. -type StateTransformer struct { - // ConcreteCurrent and ConcreteDeposed are used to specialize the abstract - // resource instance nodes that this transformer will create. - // - // If either of these is nil, the objects of that type will be skipped and - // not added to the graph at all. It doesn't make sense to use this - // transformer without setting at least one of these, since that would - // skip everything and thus be a no-op. - ConcreteCurrent ConcreteResourceInstanceNodeFunc - ConcreteDeposed ConcreteResourceInstanceDeposedNodeFunc - - State *states.State -} - -func (t *StateTransformer) Transform(g *Graph) error { - if t.State == nil { - log.Printf("[TRACE] StateTransformer: state is nil, so nothing to do") - return nil - } - - switch { - case t.ConcreteCurrent != nil && t.ConcreteDeposed != nil: - log.Printf("[TRACE] StateTransformer: creating nodes for both current and deposed instance objects") - case t.ConcreteCurrent != nil: - log.Printf("[TRACE] StateTransformer: creating nodes for current instance objects only") - case t.ConcreteDeposed != nil: - log.Printf("[TRACE] StateTransformer: creating nodes for deposed instance objects only") - default: - log.Printf("[TRACE] StateTransformer: pointless no-op call, creating no nodes at all") - } - - for _, ms := range t.State.Modules { - for _, rs := range ms.Resources { - resourceAddr := rs.Addr - - for key, is := range rs.Instances { - addr := resourceAddr.Instance(key) - - if obj := is.Current; obj != nil && t.ConcreteCurrent != nil { - abstract := NewNodeAbstractResourceInstance(addr) - node := t.ConcreteCurrent(abstract) - g.Add(node) - log.Printf("[TRACE] StateTransformer: added %T for %s current object", node, addr) - } - - if t.ConcreteDeposed != nil { - for dk := range is.Deposed { - abstract := NewNodeAbstractResourceInstance(addr) - node := t.ConcreteDeposed(abstract, dk) - g.Add(node) - log.Printf("[TRACE] StateTransformer: added %T for %s deposed object %s", node, addr, dk) - } - } - } - } - } - - return nil -} diff --git a/internal/terraform/transform_targets.go b/internal/terraform/transform_targets.go deleted file mode 100644 index e603bcedb417..000000000000 --- a/internal/terraform/transform_targets.go +++ /dev/null @@ -1,159 +0,0 @@ -package terraform - -import ( - "log" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/dag" -) - -// GraphNodeTargetable is an interface for graph nodes to implement when they -// need to be told about incoming targets. This is useful for nodes that need -// to respect targets as they dynamically expand. Note that the list of targets -// provided will contain every target provided, and each implementing graph -// node must filter this list to targets considered relevant. -type GraphNodeTargetable interface { - SetTargets([]addrs.Targetable) -} - -// TargetsTransformer is a GraphTransformer that, when the user specifies a -// list of resources to target, limits the graph to only those resources and -// their dependencies. -type TargetsTransformer struct { - // List of targeted resource names specified by the user - Targets []addrs.Targetable -} - -func (t *TargetsTransformer) Transform(g *Graph) error { - if len(t.Targets) > 0 { - targetedNodes, err := t.selectTargetedNodes(g, t.Targets) - if err != nil { - return err - } - - for _, v := range g.Vertices() { - if !targetedNodes.Include(v) { - log.Printf("[DEBUG] Removing %q, filtered by targeting.", dag.VertexName(v)) - g.Remove(v) - } - } - } - - return nil -} - -// Returns a set of targeted nodes. A targeted node is either addressed -// directly, address indirectly via its container, or it's a dependency of a -// targeted node. -func (t *TargetsTransformer) selectTargetedNodes(g *Graph, addrs []addrs.Targetable) (dag.Set, error) { - targetedNodes := make(dag.Set) - - vertices := g.Vertices() - - for _, v := range vertices { - if t.nodeIsTarget(v, addrs) { - targetedNodes.Add(v) - - // We inform nodes that ask about the list of targets - helps for nodes - // that need to dynamically expand. Note that this only occurs for nodes - // that are already directly targeted. - if tn, ok := v.(GraphNodeTargetable); ok { - tn.SetTargets(addrs) - } - - deps, _ := g.Ancestors(v) - for _, d := range deps { - targetedNodes.Add(d) - } - } - } - - // It is expected that outputs which are only derived from targeted - // resources are also updated. While we don't include any other possible - // side effects from the targeted nodes, these are added because outputs - // cannot be targeted on their own. - // Start by finding the root module output nodes themselves - for _, v := range vertices { - // outputs are all temporary value types - tv, ok := v.(graphNodeTemporaryValue) - if !ok { - continue - } - - // root module outputs indicate that while they are an output type, - // they not temporary and will return false here. - if tv.temporaryValue() { - continue - } - - // If this output is descended only from targeted resources, then we - // will keep it - deps, _ := g.Ancestors(v) - found := 0 - for _, d := range deps { - switch d.(type) { - case GraphNodeResourceInstance: - case GraphNodeConfigResource: - default: - continue - } - - if !targetedNodes.Include(d) { - // this dependency isn't being targeted, so we can't process this - // output - found = 0 - break - } - - found++ - } - - if found > 0 { - // we found an output we can keep; add it, and all it's dependencies - targetedNodes.Add(v) - for _, d := range deps { - targetedNodes.Add(d) - } - } - } - - return targetedNodes, nil -} - -func (t *TargetsTransformer) nodeIsTarget(v dag.Vertex, targets []addrs.Targetable) bool { - var vertexAddr addrs.Targetable - switch r := v.(type) { - case GraphNodeResourceInstance: - vertexAddr = r.ResourceInstanceAddr() - case GraphNodeConfigResource: - vertexAddr = r.ResourceAddr() - - default: - // Only resource and resource instance nodes can be targeted. - return false - } - - for _, targetAddr := range targets { - switch vertexAddr.(type) { - case addrs.ConfigResource: - // Before expansion happens, we only have nodes that know their - // ConfigResource address. We need to take the more specific - // target addresses and generalize them in order to compare with a - // ConfigResource. - switch target := targetAddr.(type) { - case addrs.AbsResourceInstance: - targetAddr = target.ContainingResource().Config() - case addrs.AbsResource: - targetAddr = target.Config() - case addrs.ModuleInstance: - targetAddr = target.Module() - } - } - - if targetAddr.TargetContains(vertexAddr) { - return true - } - } - - return false -} diff --git a/internal/terraform/transform_targets_test.go b/internal/terraform/transform_targets_test.go deleted file mode 100644 index 0ed95c080978..000000000000 --- a/internal/terraform/transform_targets_test.go +++ /dev/null @@ -1,202 +0,0 @@ -package terraform - -import ( - "strings" - "testing" - - "github.com/hashicorp/terraform/internal/addrs" -) - -func TestTargetsTransformer(t *testing.T) { - mod := testModule(t, "transform-targets-basic") - - g := Graph{Path: addrs.RootModuleInstance} - { - tf := &ConfigTransformer{Config: mod} - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - } - - { - transform := &AttachResourceConfigTransformer{Config: mod} - if err := transform.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - } - - { - transform := &ReferenceTransformer{} - if err := transform.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - } - - { - transform := &TargetsTransformer{ - Targets: []addrs.Targetable{ - addrs.RootModuleInstance.Resource( - addrs.ManagedResourceMode, "aws_instance", "me", - ), - }, - } - if err := transform.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(` -aws_instance.me - aws_subnet.me -aws_subnet.me - aws_vpc.me -aws_vpc.me - `) - if actual != expected { - t.Fatalf("bad:\n\nexpected:\n%s\n\ngot:\n%s\n", expected, actual) - } -} - -func TestTargetsTransformer_downstream(t *testing.T) { - mod := testModule(t, "transform-targets-downstream") - - g := Graph{Path: addrs.RootModuleInstance} - { - transform := &ConfigTransformer{Config: mod} - if err := transform.Transform(&g); err != nil { - t.Fatalf("%T failed: %s", transform, err) - } - } - - { - transform := &AttachResourceConfigTransformer{Config: mod} - if err := transform.Transform(&g); err != nil { - t.Fatalf("%T failed: %s", transform, err) - } - } - - { - transform := &AttachResourceConfigTransformer{Config: mod} - if err := transform.Transform(&g); err != nil { - t.Fatalf("%T failed: %s", transform, err) - } - } - - { - transform := &OutputTransformer{Config: mod} - if err := transform.Transform(&g); err != nil { - t.Fatalf("%T failed: %s", transform, err) - } - } - - { - transform := &ReferenceTransformer{} - if err := transform.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - } - - { - transform := &TargetsTransformer{ - Targets: []addrs.Targetable{ - addrs.RootModuleInstance. - Child("child", addrs.NoKey). - Child("grandchild", addrs.NoKey). - Resource( - addrs.ManagedResourceMode, "aws_instance", "foo", - ), - }, - } - if err := transform.Transform(&g); err != nil { - t.Fatalf("%T failed: %s", transform, err) - } - } - - actual := strings.TrimSpace(g.String()) - // Even though we only asked to target the grandchild resource, all of the - // outputs that descend from it are also targeted. - expected := strings.TrimSpace(` -module.child.module.grandchild.aws_instance.foo -module.child.module.grandchild.output.id (expand) - module.child.module.grandchild.aws_instance.foo -module.child.output.grandchild_id (expand) - module.child.module.grandchild.output.id (expand) -output.grandchild_id (expand) - module.child.output.grandchild_id (expand) - `) - if actual != expected { - t.Fatalf("bad:\n\nexpected:\n%s\n\ngot:\n%s\n", expected, actual) - } -} - -// This tests the TargetsTransformer targeting a whole module, -// rather than a resource within a module instance. -func TestTargetsTransformer_wholeModule(t *testing.T) { - mod := testModule(t, "transform-targets-downstream") - - g := Graph{Path: addrs.RootModuleInstance} - { - transform := &ConfigTransformer{Config: mod} - if err := transform.Transform(&g); err != nil { - t.Fatalf("%T failed: %s", transform, err) - } - } - - { - transform := &AttachResourceConfigTransformer{Config: mod} - if err := transform.Transform(&g); err != nil { - t.Fatalf("%T failed: %s", transform, err) - } - } - - { - transform := &AttachResourceConfigTransformer{Config: mod} - if err := transform.Transform(&g); err != nil { - t.Fatalf("%T failed: %s", transform, err) - } - } - - { - transform := &OutputTransformer{Config: mod} - if err := transform.Transform(&g); err != nil { - t.Fatalf("%T failed: %s", transform, err) - } - } - - { - transform := &ReferenceTransformer{} - if err := transform.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - } - - { - transform := &TargetsTransformer{ - Targets: []addrs.Targetable{ - addrs.RootModule. - Child("child"). - Child("grandchild"), - }, - } - if err := transform.Transform(&g); err != nil { - t.Fatalf("%T failed: %s", transform, err) - } - } - - actual := strings.TrimSpace(g.String()) - // Even though we only asked to target the grandchild module, all of the - // outputs that descend from it are also targeted. - expected := strings.TrimSpace(` -module.child.module.grandchild.aws_instance.foo -module.child.module.grandchild.output.id (expand) - module.child.module.grandchild.aws_instance.foo -module.child.output.grandchild_id (expand) - module.child.module.grandchild.output.id (expand) -output.grandchild_id (expand) - module.child.output.grandchild_id (expand) - `) - if actual != expected { - t.Fatalf("bad:\n\nexpected:\n%s\n\ngot:\n%s\n", expected, actual) - } -} diff --git a/internal/terraform/transform_transitive_reduction.go b/internal/terraform/transform_transitive_reduction.go deleted file mode 100644 index 0bb6cb377336..000000000000 --- a/internal/terraform/transform_transitive_reduction.go +++ /dev/null @@ -1,20 +0,0 @@ -package terraform - -// TransitiveReductionTransformer is a GraphTransformer that -// finds the transitive reduction of the graph. For a definition of -// transitive reduction, see [Wikipedia](https://en.wikipedia.org/wiki/Transitive_reduction). -type TransitiveReductionTransformer struct{} - -func (t *TransitiveReductionTransformer) Transform(g *Graph) error { - // If the graph isn't valid, skip the transitive reduction. - // We don't error here because Terraform itself handles graph - // validation in a better way, or we assume it does. - if err := g.Validate(); err != nil { - return nil - } - - // Do it - g.TransitiveReduction() - - return nil -} diff --git a/internal/terraform/transform_transitive_reduction_test.go b/internal/terraform/transform_transitive_reduction_test.go deleted file mode 100644 index 1339d071fec2..000000000000 --- a/internal/terraform/transform_transitive_reduction_test.go +++ /dev/null @@ -1,86 +0,0 @@ -package terraform - -import ( - "strings" - "testing" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/zclconf/go-cty/cty" -) - -func TestTransitiveReductionTransformer(t *testing.T) { - mod := testModule(t, "transform-trans-reduce-basic") - - g := Graph{Path: addrs.RootModuleInstance} - { - tf := &ConfigTransformer{Config: mod} - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - t.Logf("graph after ConfigTransformer:\n%s", g.String()) - } - - { - transform := &AttachResourceConfigTransformer{Config: mod} - if err := transform.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - } - - { - transform := &AttachSchemaTransformer{ - Plugins: schemaOnlyProvidersForTesting(map[addrs.Provider]*ProviderSchema{ - addrs.NewDefaultProvider("aws"): { - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": { - Attributes: map[string]*configschema.Attribute{ - "A": { - Type: cty.String, - Optional: true, - }, - "B": { - Type: cty.String, - Optional: true, - }, - }, - }, - }, - }, - }), - } - if err := transform.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - } - - { - transform := &ReferenceTransformer{} - if err := transform.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - t.Logf("graph after ReferenceTransformer:\n%s", g.String()) - } - - { - transform := &TransitiveReductionTransformer{} - if err := transform.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - t.Logf("graph after TransitiveReductionTransformer:\n%s", g.String()) - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(testTransformTransReduceBasicStr) - if actual != expected { - t.Errorf("wrong result\ngot:\n%s\n\nwant:\n%s", actual, expected) - } -} - -const testTransformTransReduceBasicStr = ` -aws_instance.A -aws_instance.B - aws_instance.A -aws_instance.C - aws_instance.B -` diff --git a/internal/terraform/transform_variable.go b/internal/terraform/transform_variable.go deleted file mode 100644 index 4262ea3d6db0..000000000000 --- a/internal/terraform/transform_variable.go +++ /dev/null @@ -1,43 +0,0 @@ -package terraform - -import ( - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" -) - -// RootVariableTransformer is a GraphTransformer that adds all the root -// variables to the graph. -// -// Root variables are currently no-ops but they must be added to the -// graph since downstream things that depend on them must be able to -// reach them. -type RootVariableTransformer struct { - Config *configs.Config - - RawValues InputValues -} - -func (t *RootVariableTransformer) Transform(g *Graph) error { - // We can have no variables if we have no config. - if t.Config == nil { - return nil - } - - // We're only considering root module variables here, since child - // module variables are handled by ModuleVariableTransformer. - vars := t.Config.Module.Variables - - // Add all variables here - for _, v := range vars { - node := &NodeRootVariable{ - Addr: addrs.InputVariable{ - Name: v.Name, - }, - Config: v, - RawValue: t.RawValues[v.Name], - } - g.Add(node) - } - - return nil -} diff --git a/internal/terraform/transform_vertex.go b/internal/terraform/transform_vertex.go deleted file mode 100644 index 6dd2f98dce31..000000000000 --- a/internal/terraform/transform_vertex.go +++ /dev/null @@ -1,44 +0,0 @@ -package terraform - -import ( - "fmt" - - "github.com/hashicorp/terraform/internal/dag" -) - -// VertexTransformer is a GraphTransformer that transforms vertices -// using the GraphVertexTransformers. The Transforms are run in sequential -// order. If a transform replaces a vertex then the next transform will see -// the new vertex. -type VertexTransformer struct { - Transforms []GraphVertexTransformer -} - -func (t *VertexTransformer) Transform(g *Graph) error { - for _, v := range g.Vertices() { - for _, vt := range t.Transforms { - newV, err := vt.Transform(v) - if err != nil { - return err - } - - // If the vertex didn't change, then don't do anything more - if newV == v { - continue - } - - // Vertex changed, replace it within the graph - if ok := g.Replace(v, newV); !ok { - // This should never happen, big problem - return fmt.Errorf( - "failed to replace %s with %s!\n\nSource: %#v\n\nTarget: %#v", - dag.VertexName(v), dag.VertexName(newV), v, newV) - } - - // Replace v so that future transforms use the proper vertex - v = newV - } - } - - return nil -} diff --git a/internal/terraform/transform_vertex_test.go b/internal/terraform/transform_vertex_test.go deleted file mode 100644 index 21d5d914a728..000000000000 --- a/internal/terraform/transform_vertex_test.go +++ /dev/null @@ -1,58 +0,0 @@ -package terraform - -import ( - "strings" - "testing" - - "github.com/hashicorp/terraform/internal/dag" -) - -func TestVertexTransformer_impl(t *testing.T) { - var _ GraphTransformer = new(VertexTransformer) -} - -func TestVertexTransformer(t *testing.T) { - var g Graph - g.Add(1) - g.Add(2) - g.Add(3) - g.Connect(dag.BasicEdge(1, 2)) - g.Connect(dag.BasicEdge(2, 3)) - - { - tf := &VertexTransformer{ - Transforms: []GraphVertexTransformer{ - &testVertexTransform{Source: 2, Target: 42}, - }, - } - if err := tf.Transform(&g); err != nil { - t.Fatalf("err: %s", err) - } - } - - actual := strings.TrimSpace(g.String()) - expected := strings.TrimSpace(testVertexTransformerStr) - if actual != expected { - t.Fatalf("bad: %s", actual) - } -} - -type testVertexTransform struct { - Source, Target dag.Vertex -} - -func (t *testVertexTransform) Transform(v dag.Vertex) (dag.Vertex, error) { - if t.Source == v { - v = t.Target - } - - return v, nil -} - -const testVertexTransformerStr = ` -1 - 42 -3 -42 - 3 -` diff --git a/internal/terraform/ui_input.go b/internal/terraform/ui_input.go deleted file mode 100644 index 688bcf71e43c..000000000000 --- a/internal/terraform/ui_input.go +++ /dev/null @@ -1,32 +0,0 @@ -package terraform - -import "context" - -// UIInput is the interface that must be implemented to ask for input -// from this user. This should forward the request to wherever the user -// inputs things to ask for values. -type UIInput interface { - Input(context.Context, *InputOpts) (string, error) -} - -// InputOpts are options for asking for input. -type InputOpts struct { - // Id is a unique ID for the question being asked that might be - // used for logging or to look up a prior answered question. - Id string - - // Query is a human-friendly question for inputting this value. - Query string - - // Description is a description about what this option is. Be wary - // that this will probably be in a terminal so split lines as you see - // necessary. - Description string - - // Default will be the value returned if no data is entered. - Default string - - // Secret should be true if we are asking for sensitive input. - // If attached to a TTY, Terraform will disable echo. - Secret bool -} diff --git a/internal/terraform/ui_input_mock.go b/internal/terraform/ui_input_mock.go deleted file mode 100644 index e2d9c3848193..000000000000 --- a/internal/terraform/ui_input_mock.go +++ /dev/null @@ -1,25 +0,0 @@ -package terraform - -import "context" - -// MockUIInput is an implementation of UIInput that can be used for tests. -type MockUIInput struct { - InputCalled bool - InputOpts *InputOpts - InputReturnMap map[string]string - InputReturnString string - InputReturnError error - InputFn func(*InputOpts) (string, error) -} - -func (i *MockUIInput) Input(ctx context.Context, opts *InputOpts) (string, error) { - i.InputCalled = true - i.InputOpts = opts - if i.InputFn != nil { - return i.InputFn(opts) - } - if i.InputReturnMap != nil { - return i.InputReturnMap[opts.Id], i.InputReturnError - } - return i.InputReturnString, i.InputReturnError -} diff --git a/internal/terraform/ui_input_prefix.go b/internal/terraform/ui_input_prefix.go deleted file mode 100644 index b5d32b1e85d5..000000000000 --- a/internal/terraform/ui_input_prefix.go +++ /dev/null @@ -1,20 +0,0 @@ -package terraform - -import ( - "context" - "fmt" -) - -// PrefixUIInput is an implementation of UIInput that prefixes the ID -// with a string, allowing queries to be namespaced. -type PrefixUIInput struct { - IdPrefix string - QueryPrefix string - UIInput UIInput -} - -func (i *PrefixUIInput) Input(ctx context.Context, opts *InputOpts) (string, error) { - opts.Id = fmt.Sprintf("%s.%s", i.IdPrefix, opts.Id) - opts.Query = fmt.Sprintf("%s%s", i.QueryPrefix, opts.Query) - return i.UIInput.Input(ctx, opts) -} diff --git a/internal/terraform/ui_input_prefix_test.go b/internal/terraform/ui_input_prefix_test.go deleted file mode 100644 index dff42c39c5f8..000000000000 --- a/internal/terraform/ui_input_prefix_test.go +++ /dev/null @@ -1,27 +0,0 @@ -package terraform - -import ( - "context" - "testing" -) - -func TestPrefixUIInput_impl(t *testing.T) { - var _ UIInput = new(PrefixUIInput) -} - -func TestPrefixUIInput(t *testing.T) { - input := new(MockUIInput) - prefix := &PrefixUIInput{ - IdPrefix: "foo", - UIInput: input, - } - - _, err := prefix.Input(context.Background(), &InputOpts{Id: "bar"}) - if err != nil { - t.Fatalf("err: %s", err) - } - - if input.InputOpts.Id != "foo.bar" { - t.Fatalf("bad: %#v", input.InputOpts) - } -} diff --git a/internal/terraform/ui_output.go b/internal/terraform/ui_output.go deleted file mode 100644 index 84427c63de1f..000000000000 --- a/internal/terraform/ui_output.go +++ /dev/null @@ -1,7 +0,0 @@ -package terraform - -// UIOutput is the interface that must be implemented to output -// data to the end user. -type UIOutput interface { - Output(string) -} diff --git a/internal/terraform/ui_output_callback.go b/internal/terraform/ui_output_callback.go deleted file mode 100644 index 135a91c5f0a6..000000000000 --- a/internal/terraform/ui_output_callback.go +++ /dev/null @@ -1,9 +0,0 @@ -package terraform - -type CallbackUIOutput struct { - OutputFn func(string) -} - -func (o *CallbackUIOutput) Output(v string) { - o.OutputFn(v) -} diff --git a/internal/terraform/ui_output_callback_test.go b/internal/terraform/ui_output_callback_test.go deleted file mode 100644 index 1dd5ccddf9e8..000000000000 --- a/internal/terraform/ui_output_callback_test.go +++ /dev/null @@ -1,9 +0,0 @@ -package terraform - -import ( - "testing" -) - -func TestCallbackUIOutput_impl(t *testing.T) { - var _ UIOutput = new(CallbackUIOutput) -} diff --git a/internal/terraform/ui_output_mock.go b/internal/terraform/ui_output_mock.go deleted file mode 100644 index d828c921ca3f..000000000000 --- a/internal/terraform/ui_output_mock.go +++ /dev/null @@ -1,21 +0,0 @@ -package terraform - -import "sync" - -// MockUIOutput is an implementation of UIOutput that can be used for tests. -type MockUIOutput struct { - sync.Mutex - OutputCalled bool - OutputMessage string - OutputFn func(string) -} - -func (o *MockUIOutput) Output(v string) { - o.Lock() - defer o.Unlock() - o.OutputCalled = true - o.OutputMessage = v - if o.OutputFn != nil { - o.OutputFn(v) - } -} diff --git a/internal/terraform/ui_output_mock_test.go b/internal/terraform/ui_output_mock_test.go deleted file mode 100644 index 0a23c2e2349a..000000000000 --- a/internal/terraform/ui_output_mock_test.go +++ /dev/null @@ -1,9 +0,0 @@ -package terraform - -import ( - "testing" -) - -func TestMockUIOutput(t *testing.T) { - var _ UIOutput = new(MockUIOutput) -} diff --git a/internal/terraform/ui_output_provisioner.go b/internal/terraform/ui_output_provisioner.go deleted file mode 100644 index 22e5670cbd44..000000000000 --- a/internal/terraform/ui_output_provisioner.go +++ /dev/null @@ -1,19 +0,0 @@ -package terraform - -import ( - "github.com/hashicorp/terraform/internal/addrs" -) - -// ProvisionerUIOutput is an implementation of UIOutput that calls a hook -// for the output so that the hooks can handle it. -type ProvisionerUIOutput struct { - InstanceAddr addrs.AbsResourceInstance - ProvisionerType string - Hooks []Hook -} - -func (o *ProvisionerUIOutput) Output(msg string) { - for _, h := range o.Hooks { - h.ProvisionOutput(o.InstanceAddr, o.ProvisionerType, msg) - } -} diff --git a/internal/terraform/ui_output_provisioner_test.go b/internal/terraform/ui_output_provisioner_test.go deleted file mode 100644 index baadd31817fd..000000000000 --- a/internal/terraform/ui_output_provisioner_test.go +++ /dev/null @@ -1,36 +0,0 @@ -package terraform - -import ( - "testing" - - "github.com/hashicorp/terraform/internal/addrs" -) - -func TestProvisionerUIOutput_impl(t *testing.T) { - var _ UIOutput = new(ProvisionerUIOutput) -} - -func TestProvisionerUIOutputOutput(t *testing.T) { - hook := new(MockHook) - output := &ProvisionerUIOutput{ - InstanceAddr: addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_thing", - Name: "test", - }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - ProvisionerType: "foo", - Hooks: []Hook{hook}, - } - - output.Output("bar") - - if !hook.ProvisionOutputCalled { - t.Fatal("hook.ProvisionOutput was not called, and should've been") - } - if got, want := hook.ProvisionOutputProvisionerType, "foo"; got != want { - t.Fatalf("wrong provisioner type\ngot: %q\nwant: %q", got, want) - } - if got, want := hook.ProvisionOutputMessage, "bar"; got != want { - t.Fatalf("wrong output message\ngot: %q\nwant: %q", got, want) - } -} diff --git a/internal/terraform/update_state_hook.go b/internal/terraform/update_state_hook.go deleted file mode 100644 index c2ed76e8ece3..000000000000 --- a/internal/terraform/update_state_hook.go +++ /dev/null @@ -1,19 +0,0 @@ -package terraform - -// updateStateHook calls the PostStateUpdate hook with the current state. -func updateStateHook(ctx EvalContext) error { - // In principle we could grab the lock here just long enough to take a - // deep copy and then pass that to our hooks below, but we'll instead - // hold the hook for the duration to avoid the potential confusing - // situation of us racing to call PostStateUpdate concurrently with - // different state snapshots. - stateSync := ctx.State() - state := stateSync.Lock().DeepCopy() - defer stateSync.Unlock() - - // Call the hook - err := ctx.Hook(func(h Hook) (HookAction, error) { - return h.PostStateUpdate(state) - }) - return err -} diff --git a/internal/terraform/update_state_hook_test.go b/internal/terraform/update_state_hook_test.go deleted file mode 100644 index ac3e33f55dc1..000000000000 --- a/internal/terraform/update_state_hook_test.go +++ /dev/null @@ -1,33 +0,0 @@ -package terraform - -import ( - "testing" - - "github.com/davecgh/go-spew/spew" - "github.com/zclconf/go-cty/cty" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/states" -) - -func TestUpdateStateHook(t *testing.T) { - mockHook := new(MockHook) - - state := states.NewState() - state.Module(addrs.RootModuleInstance).SetLocalValue("foo", cty.StringVal("hello")) - - ctx := new(MockEvalContext) - ctx.HookHook = mockHook - ctx.StateState = state.SyncWrapper() - - if err := updateStateHook(ctx); err != nil { - t.Fatalf("err: %s", err) - } - - if !mockHook.PostStateUpdateCalled { - t.Fatal("should call PostStateUpdate") - } - if mockHook.PostStateUpdateState.LocalValue(addrs.LocalValue{Name: "foo"}.Absolute(addrs.RootModuleInstance)) != cty.StringVal("hello") { - t.Fatalf("wrong state passed to hook: %s", spew.Sdump(mockHook.PostStateUpdateState)) - } -} diff --git a/internal/terraform/upgrade_resource_state.go b/internal/terraform/upgrade_resource_state.go deleted file mode 100644 index 906898e281a0..000000000000 --- a/internal/terraform/upgrade_resource_state.go +++ /dev/null @@ -1,206 +0,0 @@ -package terraform - -import ( - "encoding/json" - "fmt" - "log" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" - "github.com/zclconf/go-cty/cty" -) - -// upgradeResourceState will, if necessary, run the provider-defined upgrade -// logic against the given state object to make it compliant with the -// current schema version. This is a no-op if the given state object is -// already at the latest version. -// -// If any errors occur during upgrade, error diagnostics are returned. In that -// case it is not safe to proceed with using the original state object. -func upgradeResourceState(addr addrs.AbsResourceInstance, provider providers.Interface, src *states.ResourceInstanceObjectSrc, currentSchema *configschema.Block, currentVersion uint64) (*states.ResourceInstanceObjectSrc, tfdiags.Diagnostics) { - if addr.Resource.Resource.Mode != addrs.ManagedResourceMode { - // We only do state upgrading for managed resources. - // This was a part of the normal workflow in older versions and - // returned early, so we are only going to log the error for now. - log.Printf("[ERROR] data resource %s should not require state upgrade", addr) - return src, nil - } - - // Remove any attributes from state that are not present in the schema. - // This was previously taken care of by the provider, but data sources do - // not go through the UpgradeResourceState process. - // - // Legacy flatmap state is already taken care of during conversion. - // If the schema version is be changed, then allow the provider to handle - // removed attributes. - if len(src.AttrsJSON) > 0 && src.SchemaVersion == currentVersion { - src.AttrsJSON = stripRemovedStateAttributes(src.AttrsJSON, currentSchema.ImpliedType()) - } - - stateIsFlatmap := len(src.AttrsJSON) == 0 - - // TODO: This should eventually use a proper FQN. - providerType := addr.Resource.Resource.ImpliedProvider() - if src.SchemaVersion > currentVersion { - log.Printf("[TRACE] upgradeResourceState: can't downgrade state for %s from version %d to %d", addr, src.SchemaVersion, currentVersion) - var diags tfdiags.Diagnostics - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Resource instance managed by newer provider version", - // This is not a very good error message, but we don't retain enough - // information in state to give good feedback on what provider - // version might be required here. :( - fmt.Sprintf("The current state of %s was created by a newer provider version than is currently selected. Upgrade the %s provider to work with this state.", addr, providerType), - )) - return nil, diags - } - - // If we get down here then we need to upgrade the state, with the - // provider's help. - // If this state was originally created by a version of Terraform prior to - // v0.12, this also includes translating from legacy flatmap to new-style - // representation, since only the provider has enough information to - // understand a flatmap built against an older schema. - if src.SchemaVersion != currentVersion { - log.Printf("[TRACE] upgradeResourceState: upgrading state for %s from version %d to %d using provider %q", addr, src.SchemaVersion, currentVersion, providerType) - } else { - log.Printf("[TRACE] upgradeResourceState: schema version of %s is still %d; calling provider %q for any other minor fixups", addr, currentVersion, providerType) - } - - req := providers.UpgradeResourceStateRequest{ - TypeName: addr.Resource.Resource.Type, - - // TODO: The internal schema version representations are all using - // uint64 instead of int64, but unsigned integers aren't friendly - // to all protobuf target languages so in practice we use int64 - // on the wire. In future we will change all of our internal - // representations to int64 too. - Version: int64(src.SchemaVersion), - } - - if stateIsFlatmap { - req.RawStateFlatmap = src.AttrsFlat - } else { - req.RawStateJSON = src.AttrsJSON - } - - resp := provider.UpgradeResourceState(req) - diags := resp.Diagnostics - if diags.HasErrors() { - return nil, diags - } - - // After upgrading, the new value must conform to the current schema. When - // going over RPC this is actually already ensured by the - // marshaling/unmarshaling of the new value, but we'll check it here - // anyway for robustness, e.g. for in-process providers. - newValue := resp.UpgradedState - if errs := newValue.Type().TestConformance(currentSchema.ImpliedType()); len(errs) > 0 { - for _, err := range errs { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Invalid resource state upgrade", - fmt.Sprintf("The %s provider upgraded the state for %s from a previous version, but produced an invalid result: %s.", providerType, addr, tfdiags.FormatError(err)), - )) - } - return nil, diags - } - - new, err := src.CompleteUpgrade(newValue, currentSchema.ImpliedType(), uint64(currentVersion)) - if err != nil { - // We already checked for type conformance above, so getting into this - // codepath should be rare and is probably a bug somewhere under CompleteUpgrade. - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Failed to encode result of resource state upgrade", - fmt.Sprintf("Failed to encode state for %s after resource schema upgrade: %s.", addr, tfdiags.FormatError(err)), - )) - } - return new, diags -} - -// stripRemovedStateAttributes deletes any attributes no longer present in the -// schema, so that the json can be correctly decoded. -func stripRemovedStateAttributes(state []byte, ty cty.Type) []byte { - jsonMap := map[string]interface{}{} - err := json.Unmarshal(state, &jsonMap) - if err != nil { - // we just log any errors here, and let the normal decode process catch - // invalid JSON. - log.Printf("[ERROR] UpgradeResourceState: stripRemovedStateAttributes: %s", err) - return state - } - - // if no changes were made, we return the original state to ensure nothing - // was altered in the marshaling process. - if !removeRemovedAttrs(jsonMap, ty) { - return state - } - - js, err := json.Marshal(jsonMap) - if err != nil { - // if the json map was somehow mangled enough to not marhsal, something - // went horribly wrong - panic(err) - } - - return js -} - -// strip out the actual missing attributes, and return a bool indicating if any -// changes were made. -func removeRemovedAttrs(v interface{}, ty cty.Type) bool { - modified := false - // we're only concerned with finding maps that correspond to object - // attributes - switch v := v.(type) { - case []interface{}: - switch { - // If these aren't blocks the next call will be a noop - case ty.IsListType() || ty.IsSetType(): - eTy := ty.ElementType() - for _, eV := range v { - modified = removeRemovedAttrs(eV, eTy) || modified - } - } - return modified - case map[string]interface{}: - switch { - case ty.IsMapType(): - // map blocks aren't yet supported, but handle this just in case - eTy := ty.ElementType() - for _, eV := range v { - modified = removeRemovedAttrs(eV, eTy) || modified - } - return modified - - case ty == cty.DynamicPseudoType: - log.Printf("[DEBUG] UpgradeResourceState: ignoring dynamic block: %#v\n", v) - return false - - case ty.IsObjectType(): - attrTypes := ty.AttributeTypes() - for attr, attrV := range v { - attrTy, ok := attrTypes[attr] - if !ok { - log.Printf("[DEBUG] UpgradeResourceState: attribute %q no longer present in schema", attr) - delete(v, attr) - modified = true - continue - } - - modified = removeRemovedAttrs(attrV, attrTy) || modified - } - return modified - default: - // This shouldn't happen, and will fail to decode further on, so - // there's no need to handle it here. - log.Printf("[WARN] UpgradeResourceState: unexpected type %#v for map in json state", ty) - return false - } - } - return modified -} diff --git a/internal/terraform/upgrade_resource_state_test.go b/internal/terraform/upgrade_resource_state_test.go deleted file mode 100644 index 11ef77b5f374..000000000000 --- a/internal/terraform/upgrade_resource_state_test.go +++ /dev/null @@ -1,148 +0,0 @@ -package terraform - -import ( - "reflect" - "testing" - - "github.com/zclconf/go-cty/cty" -) - -func TestStripRemovedStateAttributes(t *testing.T) { - cases := []struct { - name string - state map[string]interface{} - expect map[string]interface{} - ty cty.Type - modified bool - }{ - { - "removed string", - map[string]interface{}{ - "a": "ok", - "b": "gone", - }, - map[string]interface{}{ - "a": "ok", - }, - cty.Object(map[string]cty.Type{ - "a": cty.String, - }), - true, - }, - { - "removed null", - map[string]interface{}{ - "a": "ok", - "b": nil, - }, - map[string]interface{}{ - "a": "ok", - }, - cty.Object(map[string]cty.Type{ - "a": cty.String, - }), - true, - }, - { - "removed nested string", - map[string]interface{}{ - "a": "ok", - "b": map[string]interface{}{ - "a": "ok", - "b": "removed", - }, - }, - map[string]interface{}{ - "a": "ok", - "b": map[string]interface{}{ - "a": "ok", - }, - }, - cty.Object(map[string]cty.Type{ - "a": cty.String, - "b": cty.Object(map[string]cty.Type{ - "a": cty.String, - }), - }), - true, - }, - { - "removed nested list", - map[string]interface{}{ - "a": "ok", - "b": map[string]interface{}{ - "a": "ok", - "b": []interface{}{"removed"}, - }, - }, - map[string]interface{}{ - "a": "ok", - "b": map[string]interface{}{ - "a": "ok", - }, - }, - cty.Object(map[string]cty.Type{ - "a": cty.String, - "b": cty.Object(map[string]cty.Type{ - "a": cty.String, - }), - }), - true, - }, - { - "removed keys in set of objs", - map[string]interface{}{ - "a": "ok", - "b": map[string]interface{}{ - "a": "ok", - "set": []interface{}{ - map[string]interface{}{ - "x": "ok", - "y": "removed", - }, - map[string]interface{}{ - "x": "ok", - "y": "removed", - }, - }, - }, - }, - map[string]interface{}{ - "a": "ok", - "b": map[string]interface{}{ - "a": "ok", - "set": []interface{}{ - map[string]interface{}{ - "x": "ok", - }, - map[string]interface{}{ - "x": "ok", - }, - }, - }, - }, - cty.Object(map[string]cty.Type{ - "a": cty.String, - "b": cty.Object(map[string]cty.Type{ - "a": cty.String, - "set": cty.Set(cty.Object(map[string]cty.Type{ - "x": cty.String, - })), - }), - }), - true, - }, - } - - for _, tc := range cases { - t.Run(tc.name, func(t *testing.T) { - modified := removeRemovedAttrs(tc.state, tc.ty) - if !reflect.DeepEqual(tc.state, tc.expect) { - t.Fatalf("expected: %#v\n got: %#v\n", tc.expect, tc.state) - } - if modified != tc.modified { - t.Fatal("incorrect return value") - } - }) - } -} diff --git a/internal/terraform/util.go b/internal/terraform/util.go deleted file mode 100644 index 7966b58dd2fe..000000000000 --- a/internal/terraform/util.go +++ /dev/null @@ -1,75 +0,0 @@ -package terraform - -import ( - "sort" -) - -// Semaphore is a wrapper around a channel to provide -// utility methods to clarify that we are treating the -// channel as a semaphore -type Semaphore chan struct{} - -// NewSemaphore creates a semaphore that allows up -// to a given limit of simultaneous acquisitions -func NewSemaphore(n int) Semaphore { - if n <= 0 { - panic("semaphore with limit <=0") - } - ch := make(chan struct{}, n) - return Semaphore(ch) -} - -// Acquire is used to acquire an available slot. -// Blocks until available. -func (s Semaphore) Acquire() { - s <- struct{}{} -} - -// TryAcquire is used to do a non-blocking acquire. -// Returns a bool indicating success -func (s Semaphore) TryAcquire() bool { - select { - case s <- struct{}{}: - return true - default: - return false - } -} - -// Release is used to return a slot. Acquire must -// be called as a pre-condition. -func (s Semaphore) Release() { - select { - case <-s: - default: - panic("release without an acquire") - } -} - -// strSliceContains checks if a given string is contained in a slice -// When anybody asks why Go needs generics, here you go. -func strSliceContains(haystack []string, needle string) bool { - for _, s := range haystack { - if s == needle { - return true - } - } - return false -} - -// deduplicate a slice of strings -func uniqueStrings(s []string) []string { - if len(s) < 2 { - return s - } - - sort.Strings(s) - result := make([]string, 1, len(s)) - result[0] = s[0] - for i := 1; i < len(s); i++ { - if s[i] != result[len(result)-1] { - result = append(result, s[i]) - } - } - return result -} diff --git a/internal/terraform/util_test.go b/internal/terraform/util_test.go deleted file mode 100644 index 8b3907e2366c..000000000000 --- a/internal/terraform/util_test.go +++ /dev/null @@ -1,91 +0,0 @@ -package terraform - -import ( - "fmt" - "reflect" - "testing" - "time" -) - -func TestSemaphore(t *testing.T) { - s := NewSemaphore(2) - timer := time.AfterFunc(time.Second, func() { - panic("deadlock") - }) - defer timer.Stop() - - s.Acquire() - if !s.TryAcquire() { - t.Fatalf("should acquire") - } - if s.TryAcquire() { - t.Fatalf("should not acquire") - } - s.Release() - s.Release() - - // This release should panic - defer func() { - r := recover() - if r == nil { - t.Fatalf("should panic") - } - }() - s.Release() -} - -func TestStrSliceContains(t *testing.T) { - if strSliceContains(nil, "foo") { - t.Fatalf("Bad") - } - if strSliceContains([]string{}, "foo") { - t.Fatalf("Bad") - } - if strSliceContains([]string{"bar"}, "foo") { - t.Fatalf("Bad") - } - if !strSliceContains([]string{"bar", "foo"}, "foo") { - t.Fatalf("Bad") - } -} - -func TestUniqueStrings(t *testing.T) { - cases := []struct { - Input []string - Expected []string - }{ - { - []string{}, - []string{}, - }, - { - []string{"x"}, - []string{"x"}, - }, - { - []string{"a", "b", "c"}, - []string{"a", "b", "c"}, - }, - { - []string{"a", "a", "a"}, - []string{"a"}, - }, - { - []string{"a", "b", "a", "b", "a", "a"}, - []string{"a", "b"}, - }, - { - []string{"c", "b", "a", "c", "b"}, - []string{"a", "b", "c"}, - }, - } - - for i, tc := range cases { - t.Run(fmt.Sprintf("unique-%d", i), func(t *testing.T) { - actual := uniqueStrings(tc.Input) - if !reflect.DeepEqual(tc.Expected, actual) { - t.Fatalf("Expected: %q\nGot: %q", tc.Expected, actual) - } - }) - } -} diff --git a/internal/terraform/validate_selfref.go b/internal/terraform/validate_selfref.go deleted file mode 100644 index ff00cded7514..000000000000 --- a/internal/terraform/validate_selfref.go +++ /dev/null @@ -1,60 +0,0 @@ -package terraform - -import ( - "fmt" - - "github.com/hashicorp/hcl/v2" - - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/lang" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -// validateSelfRef checks to ensure that expressions within a particular -// referencable block do not reference that same block. -func validateSelfRef(addr addrs.Referenceable, config hcl.Body, providerSchema *ProviderSchema) tfdiags.Diagnostics { - var diags tfdiags.Diagnostics - - addrStrs := make([]string, 0, 1) - addrStrs = append(addrStrs, addr.String()) - switch tAddr := addr.(type) { - case addrs.ResourceInstance: - // A resource instance may not refer to its containing resource either. - addrStrs = append(addrStrs, tAddr.ContainingResource().String()) - } - - if providerSchema == nil { - diags = diags.Append(fmt.Errorf("provider schema unavailable while validating %s for self-references; this is a bug in Terraform and should be reported", addr)) - return diags - } - - var schema *configschema.Block - switch tAddr := addr.(type) { - case addrs.Resource: - schema, _ = providerSchema.SchemaForResourceAddr(tAddr) - case addrs.ResourceInstance: - schema, _ = providerSchema.SchemaForResourceAddr(tAddr.ContainingResource()) - } - - if schema == nil { - diags = diags.Append(fmt.Errorf("no schema available for %s to validate for self-references; this is a bug in Terraform and should be reported", addr)) - return diags - } - - refs, _ := lang.ReferencesInBlock(config, schema) - for _, ref := range refs { - for _, addrStr := range addrStrs { - if ref.Subject.String() == addrStr { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Self-referential block", - Detail: fmt.Sprintf("Configuration for %s may not refer to itself.", addrStr), - Subject: ref.SourceRange.ToHCL().Ptr(), - }) - } - } - } - - return diags -} diff --git a/internal/terraform/validate_selfref_test.go b/internal/terraform/validate_selfref_test.go deleted file mode 100644 index 73fda25d0a01..000000000000 --- a/internal/terraform/validate_selfref_test.go +++ /dev/null @@ -1,105 +0,0 @@ -package terraform - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform/internal/configs/configschema" - - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/hcl/v2/hcltest" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/zclconf/go-cty/cty" -) - -func TestValidateSelfRef(t *testing.T) { - rAddr := addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "aws_instance", - Name: "foo", - } - - tests := []struct { - Name string - Addr addrs.Referenceable - Expr hcl.Expression - Err bool - }{ - { - "no references at all", - rAddr, - hcltest.MockExprLiteral(cty.StringVal("bar")), - false, - }, - - { - "non self reference", - rAddr, - hcltest.MockExprTraversalSrc("aws_instance.bar.id"), - false, - }, - - { - "self reference", - rAddr, - hcltest.MockExprTraversalSrc("aws_instance.foo.id"), - true, - }, - - { - "self reference other index", - rAddr, - hcltest.MockExprTraversalSrc("aws_instance.foo[4].id"), - false, - }, - - { - "self reference same index", - rAddr.Instance(addrs.IntKey(4)), - hcltest.MockExprTraversalSrc("aws_instance.foo[4].id"), - true, - }, - - { - "self reference whole", - rAddr.Instance(addrs.IntKey(4)), - hcltest.MockExprTraversalSrc("aws_instance.foo"), - true, - }, - } - - for i, test := range tests { - t.Run(fmt.Sprintf("%d-%s", i, test.Name), func(t *testing.T) { - body := hcltest.MockBody(&hcl.BodyContent{ - Attributes: hcl.Attributes{ - "foo": { - Name: "foo", - Expr: test.Expr, - }, - }, - }) - - ps := &ProviderSchema{ - ResourceTypes: map[string]*configschema.Block{ - "aws_instance": &configschema.Block{ - Attributes: map[string]*configschema.Attribute{ - "foo": { - Type: cty.String, - Required: true, - }, - }, - }, - }, - } - - diags := validateSelfRef(test.Addr, body, ps) - if diags.HasErrors() != test.Err { - if test.Err { - t.Errorf("unexpected success; want error") - } else { - t.Errorf("unexpected error\n\n%s", diags.Err()) - } - } - }) - } -} diff --git a/internal/terraform/valuesourcetype_string.go b/internal/terraform/valuesourcetype_string.go deleted file mode 100644 index 627593d762b5..000000000000 --- a/internal/terraform/valuesourcetype_string.go +++ /dev/null @@ -1,59 +0,0 @@ -// Code generated by "stringer -type ValueSourceType"; DO NOT EDIT. - -package terraform - -import "strconv" - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[ValueFromUnknown-0] - _ = x[ValueFromConfig-67] - _ = x[ValueFromAutoFile-70] - _ = x[ValueFromNamedFile-78] - _ = x[ValueFromCLIArg-65] - _ = x[ValueFromEnvVar-69] - _ = x[ValueFromInput-73] - _ = x[ValueFromPlan-80] - _ = x[ValueFromCaller-83] -} - -const ( - _ValueSourceType_name_0 = "ValueFromUnknown" - _ValueSourceType_name_1 = "ValueFromCLIArg" - _ValueSourceType_name_2 = "ValueFromConfig" - _ValueSourceType_name_3 = "ValueFromEnvVarValueFromAutoFile" - _ValueSourceType_name_4 = "ValueFromInput" - _ValueSourceType_name_5 = "ValueFromNamedFile" - _ValueSourceType_name_6 = "ValueFromPlan" - _ValueSourceType_name_7 = "ValueFromCaller" -) - -var ( - _ValueSourceType_index_3 = [...]uint8{0, 15, 32} -) - -func (i ValueSourceType) String() string { - switch { - case i == 0: - return _ValueSourceType_name_0 - case i == 65: - return _ValueSourceType_name_1 - case i == 67: - return _ValueSourceType_name_2 - case 69 <= i && i <= 70: - i -= 69 - return _ValueSourceType_name_3[_ValueSourceType_index_3[i]:_ValueSourceType_index_3[i+1]] - case i == 73: - return _ValueSourceType_name_4 - case i == 78: - return _ValueSourceType_name_5 - case i == 80: - return _ValueSourceType_name_6 - case i == 83: - return _ValueSourceType_name_7 - default: - return "ValueSourceType(" + strconv.FormatInt(int64(i), 10) + ")" - } -} diff --git a/internal/terraform/variables.go b/internal/terraform/variables.go deleted file mode 100644 index a60f187003dd..000000000000 --- a/internal/terraform/variables.go +++ /dev/null @@ -1,315 +0,0 @@ -package terraform - -import ( - "fmt" - - "github.com/zclconf/go-cty/cty" - - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/tfdiags" -) - -// InputValue represents a raw value for a root module input variable as -// provided by the external caller into a function like terraform.Context.Plan. -// -// InputValue should represent as directly as possible what the user set the -// variable to, without any attempt to convert the value to the variable's -// type constraint or substitute the configured default values for variables -// that wasn't set. Those adjustments will be handled by Terraform Core itself -// as part of performing the requested operation. -// -// A Terraform Core caller must provide an InputValue object for each of the -// variables declared in the root module, even if the end user didn't provide -// an explicit value for some of them. See the Value field documentation for -// how to handle that situation. -// -// Terraform Core also internally uses InputValue to represent the raw value -// provided for a variable in a child module call, following the same -// conventions. However, that's an implementation detail not visible to -// outside callers. -type InputValue struct { - // Value is the raw value as provided by the user as part of the plan - // options, or a corresponding similar data structure for non-plan - // operations. - // - // If a particular variable declared in the root module is _not_ set by - // the user then the caller must still provide an InputValue for it but - // must set Value to cty.NilVal to represent the absense of a value. - // This requirement is to help detect situations where the caller isn't - // correctly detecting and handling all of the declared variables. - // - // For historical reasons it's important that callers distinguish the - // situation of the value not being set at all (cty.NilVal) from the - // situation of it being explicitly set to null (a cty.NullVal result): - // for "nullable" input variables that distinction unfortunately decides - // whether the final value will be the variable's default or will be - // explicitly null. - Value cty.Value - - // SourceType is a high-level category for where the value of Value - // came from, which Terraform Core uses to tailor some of its error - // messages to be more helpful to the user. - // - // Some SourceType values should be accompanied by a populated SourceRange - // value. See that field's documentation below for more information. - SourceType ValueSourceType - - // SourceRange provides source location information for values whose - // SourceType is either ValueFromConfig, ValueFromNamedFile, or - // ValueForNormalFile. It is not populated for other source types, and so - // should not be used. - SourceRange tfdiags.SourceRange -} - -// ValueSourceType describes what broad category of source location provided -// a particular value. -type ValueSourceType rune - -const ( - // ValueFromUnknown is the zero value of ValueSourceType and is not valid. - ValueFromUnknown ValueSourceType = 0 - - // ValueFromConfig indicates that a value came from a .tf or .tf.json file, - // e.g. the default value defined for a variable. - ValueFromConfig ValueSourceType = 'C' - - // ValueFromAutoFile indicates that a value came from a "values file", like - // a .tfvars file, that was implicitly loaded by naming convention. - ValueFromAutoFile ValueSourceType = 'F' - - // ValueFromNamedFile indicates that a value came from a named "values file", - // like a .tfvars file, that was passed explicitly on the command line (e.g. - // -var-file=foo.tfvars). - ValueFromNamedFile ValueSourceType = 'N' - - // ValueFromCLIArg indicates that the value was provided directly in - // a CLI argument. The name of this argument is not recorded and so it must - // be inferred from context. - ValueFromCLIArg ValueSourceType = 'A' - - // ValueFromEnvVar indicates that the value was provided via an environment - // variable. The name of the variable is not recorded and so it must be - // inferred from context. - ValueFromEnvVar ValueSourceType = 'E' - - // ValueFromInput indicates that the value was provided at an interactive - // input prompt. - ValueFromInput ValueSourceType = 'I' - - // ValueFromPlan indicates that the value was retrieved from a stored plan. - ValueFromPlan ValueSourceType = 'P' - - // ValueFromCaller indicates that the value was explicitly overridden by - // a caller to Context.SetVariable after the context was constructed. - ValueFromCaller ValueSourceType = 'S' -) - -func (v *InputValue) GoString() string { - if (v.SourceRange != tfdiags.SourceRange{}) { - return fmt.Sprintf("&terraform.InputValue{Value: %#v, SourceType: %#v, SourceRange: %#v}", v.Value, v.SourceType, v.SourceRange) - } else { - return fmt.Sprintf("&terraform.InputValue{Value: %#v, SourceType: %#v}", v.Value, v.SourceType) - } -} - -// HasSourceRange returns true if the reciever has a source type for which -// we expect the SourceRange field to be populated with a valid range. -func (v *InputValue) HasSourceRange() bool { - return v.SourceType.HasSourceRange() -} - -// HasSourceRange returns true if the reciever is one of the source types -// that is used along with a valid SourceRange field when appearing inside an -// InputValue object. -func (v ValueSourceType) HasSourceRange() bool { - switch v { - case ValueFromConfig, ValueFromAutoFile, ValueFromNamedFile: - return true - default: - return false - } -} - -func (v ValueSourceType) GoString() string { - return fmt.Sprintf("terraform.%s", v) -} - -//go:generate go run golang.org/x/tools/cmd/stringer -type ValueSourceType - -// InputValues is a map of InputValue instances. -type InputValues map[string]*InputValue - -// InputValuesFromCaller turns the given map of naked values into an -// InputValues that attributes each value to "a caller", using the source -// type ValueFromCaller. This is primarily useful for testing purposes. -// -// This should not be used as a general way to convert map[string]cty.Value -// into InputValues, since in most real cases we want to set a suitable -// other SourceType and possibly SourceRange value. -func InputValuesFromCaller(vals map[string]cty.Value) InputValues { - ret := make(InputValues, len(vals)) - for k, v := range vals { - ret[k] = &InputValue{ - Value: v, - SourceType: ValueFromCaller, - } - } - return ret -} - -// Override merges the given value maps with the receiver, overriding any -// conflicting keys so that the latest definition wins. -func (vv InputValues) Override(others ...InputValues) InputValues { - // FIXME: This should check to see if any of the values are maps and - // merge them if so, in order to preserve the behavior from prior to - // Terraform 0.12. - ret := make(InputValues) - for k, v := range vv { - ret[k] = v - } - for _, other := range others { - for k, v := range other { - ret[k] = v - } - } - return ret -} - -// JustValues returns a map that just includes the values, discarding the -// source information. -func (vv InputValues) JustValues() map[string]cty.Value { - ret := make(map[string]cty.Value, len(vv)) - for k, v := range vv { - ret[k] = v.Value - } - return ret -} - -// SameValues returns true if the given InputValues has the same values as -// the receiever, disregarding the source types and source ranges. -// -// Values are compared using the cty "RawEquals" method, which means that -// unknown values can be considered equal to one another if they are of the -// same type. -func (vv InputValues) SameValues(other InputValues) bool { - if len(vv) != len(other) { - return false - } - - for k, v := range vv { - ov, exists := other[k] - if !exists { - return false - } - if !v.Value.RawEquals(ov.Value) { - return false - } - } - - return true -} - -// HasValues returns true if the reciever has the same values as in the given -// map, disregarding the source types and source ranges. -// -// Values are compared using the cty "RawEquals" method, which means that -// unknown values can be considered equal to one another if they are of the -// same type. -func (vv InputValues) HasValues(vals map[string]cty.Value) bool { - if len(vv) != len(vals) { - return false - } - - for k, v := range vv { - oVal, exists := vals[k] - if !exists { - return false - } - if !v.Value.RawEquals(oVal) { - return false - } - } - - return true -} - -// Identical returns true if the given InputValues has the same values, -// source types, and source ranges as the receiver. -// -// Values are compared using the cty "RawEquals" method, which means that -// unknown values can be considered equal to one another if they are of the -// same type. -// -// This method is primarily for testing. For most practical purposes, it's -// better to use SameValues or HasValues. -func (vv InputValues) Identical(other InputValues) bool { - if len(vv) != len(other) { - return false - } - - for k, v := range vv { - ov, exists := other[k] - if !exists { - return false - } - if !v.Value.RawEquals(ov.Value) { - return false - } - if v.SourceType != ov.SourceType { - return false - } - if v.SourceRange != ov.SourceRange { - return false - } - } - - return true -} - -// checkInputVariables ensures that the caller provided an InputValue -// definition for each root module variable declared in the configuration. -// The caller must provide an InputVariables with keys exactly matching -// the declared variables, though some of them may be marked explicitly -// unset by their values being cty.NilVal. -// -// This doesn't perform any type checking, default value substitution, or -// validation checks. Those are all handled during a graph walk when we -// visit the graph nodes representing each root variable. -// -// The set of values is considered valid only if the returned diagnostics -// does not contain errors. A valid set of values may still produce warnings, -// which should be returned to the user. -func checkInputVariables(vcs map[string]*configs.Variable, vs InputValues) tfdiags.Diagnostics { - var diags tfdiags.Diagnostics - - for name := range vcs { - _, isSet := vs[name] - if !isSet { - // Always an error, since the caller should have produced an - // item with Value: cty.NilVal to be explicit that it offered - // an opportunity to set this variable. - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Unassigned variable", - fmt.Sprintf("The input variable %q has not been assigned a value. This is a bug in Terraform; please report it in a GitHub issue.", name), - )) - continue - } - } - - // Check for any variables that are assigned without being configured. - // This is always an implementation error in the caller, because we - // expect undefined variables to be caught during context construction - // where there is better context to report it well. - for name := range vs { - if _, defined := vcs[name]; !defined { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Value assigned to undeclared variable", - fmt.Sprintf("A value was assigned to an undeclared input variable %q.", name), - )) - } - } - - return diags -} diff --git a/internal/terraform/variables_test.go b/internal/terraform/variables_test.go deleted file mode 100644 index 6e53a95750a2..000000000000 --- a/internal/terraform/variables_test.go +++ /dev/null @@ -1,148 +0,0 @@ -package terraform - -import ( - "testing" - - "github.com/hashicorp/terraform/internal/configs" - "github.com/zclconf/go-cty/cty" -) - -func TestCheckInputVariables(t *testing.T) { - c := testModule(t, "input-variables") - - t.Run("No variables set", func(t *testing.T) { - // No variables set - diags := checkInputVariables(c.Module.Variables, nil) - if !diags.HasErrors() { - t.Fatal("check succeeded, but want errors") - } - - // Required variables set, optional variables unset - // This is still an error at this layer, since it's the caller's - // responsibility to have already merged in any default values. - diags = checkInputVariables(c.Module.Variables, InputValues{ - "foo": &InputValue{ - Value: cty.StringVal("bar"), - SourceType: ValueFromCLIArg, - }, - }) - if !diags.HasErrors() { - t.Fatal("check succeeded, but want errors") - } - }) - - t.Run("All variables set", func(t *testing.T) { - diags := checkInputVariables(c.Module.Variables, InputValues{ - "foo": &InputValue{ - Value: cty.StringVal("bar"), - SourceType: ValueFromCLIArg, - }, - "bar": &InputValue{ - Value: cty.StringVal("baz"), - SourceType: ValueFromCLIArg, - }, - "map": &InputValue{ - Value: cty.StringVal("baz"), // okay because config has no type constraint - SourceType: ValueFromCLIArg, - }, - "object_map": &InputValue{ - Value: cty.MapVal(map[string]cty.Value{ - "uno": cty.ObjectVal(map[string]cty.Value{ - "foo": cty.StringVal("baz"), - "bar": cty.NumberIntVal(2), // type = any - }), - "dos": cty.ObjectVal(map[string]cty.Value{ - "foo": cty.StringVal("bat"), - "bar": cty.NumberIntVal(99), // type = any - }), - }), - SourceType: ValueFromCLIArg, - }, - "object_list": &InputValue{ - Value: cty.ListVal([]cty.Value{ - cty.ObjectVal(map[string]cty.Value{ - "foo": cty.StringVal("baz"), - "bar": cty.NumberIntVal(2), // type = any - }), - cty.ObjectVal(map[string]cty.Value{ - "foo": cty.StringVal("bang"), - "bar": cty.NumberIntVal(42), // type = any - }), - }), - SourceType: ValueFromCLIArg, - }, - }) - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - }) - - t.Run("Invalid Complex Types", func(t *testing.T) { - diags := checkInputVariables(c.Module.Variables, InputValues{ - "foo": &InputValue{ - Value: cty.StringVal("bar"), - SourceType: ValueFromCLIArg, - }, - "bar": &InputValue{ - Value: cty.StringVal("baz"), - SourceType: ValueFromCLIArg, - }, - "map": &InputValue{ - Value: cty.StringVal("baz"), // okay because config has no type constraint - SourceType: ValueFromCLIArg, - }, - "object_map": &InputValue{ - Value: cty.MapVal(map[string]cty.Value{ - "uno": cty.ObjectVal(map[string]cty.Value{ - "foo": cty.StringVal("baz"), - "bar": cty.NumberIntVal(2), // type = any - }), - "dos": cty.ObjectVal(map[string]cty.Value{ - "foo": cty.StringVal("bat"), - "bar": cty.NumberIntVal(99), // type = any - }), - }), - SourceType: ValueFromCLIArg, - }, - "object_list": &InputValue{ - Value: cty.TupleVal([]cty.Value{ - cty.ObjectVal(map[string]cty.Value{ - "foo": cty.StringVal("baz"), - "bar": cty.NumberIntVal(2), // type = any - }), - cty.ObjectVal(map[string]cty.Value{ - "foo": cty.StringVal("bang"), - "bar": cty.StringVal("42"), // type = any, but mismatch with the first list item - }), - }), - SourceType: ValueFromCLIArg, - }, - }) - - if diags.HasErrors() { - t.Fatalf("unexpected errors: %s", diags.Err()) - } - }) -} - -// testInputValuesUnset is a helper for constructing InputValues values for -// situations where all of the root module variables are optional and a -// test case intends to just use those default values and not override them -// at all. -// -// In other words, this constructs an InputValues with one entry per given -// input variable declaration where all of them are declared as unset. -func testInputValuesUnset(decls map[string]*configs.Variable) InputValues { - if len(decls) == 0 { - return nil - } - - ret := make(InputValues, len(decls)) - for name := range decls { - ret[name] = &InputValue{ - Value: cty.NilVal, - SourceType: ValueFromUnknown, - } - } - return ret -} diff --git a/internal/terraform/version_required.go b/internal/terraform/version_required.go deleted file mode 100644 index 1861050b9573..000000000000 --- a/internal/terraform/version_required.go +++ /dev/null @@ -1,85 +0,0 @@ -package terraform - -import ( - "fmt" - - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/tfdiags" - - "github.com/hashicorp/terraform/internal/configs" - - tfversion "github.com/hashicorp/terraform/version" -) - -// CheckCoreVersionRequirements visits each of the modules in the given -// configuration tree and verifies that any given Core version constraints -// match with the version of Terraform Core that is being used. -// -// The returned diagnostics will contain errors if any constraints do not match. -// The returned diagnostics might also return warnings, which should be -// displayed to the user. -func CheckCoreVersionRequirements(config *configs.Config) tfdiags.Diagnostics { - if config == nil { - return nil - } - - var diags tfdiags.Diagnostics - module := config.Module - - for _, constraint := range module.CoreVersionConstraints { - // Before checking if the constraints are met, check that we are not using any prerelease fields as these - // are not currently supported. - var prereleaseDiags tfdiags.Diagnostics - for _, required := range constraint.Required { - if required.Prerelease() { - prereleaseDiags = prereleaseDiags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid required_version constraint", - Detail: fmt.Sprintf( - "Prerelease version constraints are not supported: %s. Remove the prerelease information from the constraint. Prerelease versions of terraform will match constraints using their version core only.", - required.String()), - Subject: constraint.DeclRange.Ptr(), - }) - } - } - - if len(prereleaseDiags) > 0 { - // There were some prerelease fields in the constraints. Don't check the constraints as they will - // fail, and populate the diagnostics for these constraints with the prerelease diagnostics. - diags = diags.Append(prereleaseDiags) - continue - } - - if !constraint.Required.Check(tfversion.SemVer) { - switch { - case len(config.Path) == 0: - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Unsupported Terraform Core version", - Detail: fmt.Sprintf( - "This configuration does not support Terraform version %s. To proceed, either choose another supported Terraform version or update this version constraint. Version constraints are normally set for good reason, so updating the constraint may lead to other errors or unexpected behavior.", - tfversion.String(), - ), - Subject: constraint.DeclRange.Ptr(), - }) - default: - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Unsupported Terraform Core version", - Detail: fmt.Sprintf( - "Module %s (from %s) does not support Terraform version %s. To proceed, either choose another supported Terraform version or update this version constraint. Version constraints are normally set for good reason, so updating the constraint may lead to other errors or unexpected behavior.", - config.Path, config.SourceAddr, tfversion.String(), - ), - Subject: constraint.DeclRange.Ptr(), - }) - } - } - } - - for _, c := range config.Children { - childDiags := CheckCoreVersionRequirements(c) - diags = diags.Append(childDiags) - } - - return diags -} diff --git a/internal/terraform/walkoperation_string.go b/internal/terraform/walkoperation_string.go deleted file mode 100644 index 799d4dae27c7..000000000000 --- a/internal/terraform/walkoperation_string.go +++ /dev/null @@ -1,30 +0,0 @@ -// Code generated by "stringer -type=walkOperation graph_walk_operation.go"; DO NOT EDIT. - -package terraform - -import "strconv" - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[walkInvalid-0] - _ = x[walkApply-1] - _ = x[walkPlan-2] - _ = x[walkPlanDestroy-3] - _ = x[walkValidate-4] - _ = x[walkDestroy-5] - _ = x[walkImport-6] - _ = x[walkEval-7] -} - -const _walkOperation_name = "walkInvalidwalkApplywalkPlanwalkPlanDestroywalkValidatewalkDestroywalkImportwalkEval" - -var _walkOperation_index = [...]uint8{0, 11, 20, 28, 43, 55, 66, 76, 84} - -func (i walkOperation) String() string { - if i >= walkOperation(len(_walkOperation_index)-1) { - return "walkOperation(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _walkOperation_name[_walkOperation_index[i]:_walkOperation_index[i+1]] -} diff --git a/internal/ipaddr/LICENSE b/ipaddr/LICENSE similarity index 100% rename from internal/ipaddr/LICENSE rename to ipaddr/LICENSE diff --git a/internal/ipaddr/PATENTS b/ipaddr/PATENTS similarity index 100% rename from internal/ipaddr/PATENTS rename to ipaddr/PATENTS diff --git a/internal/ipaddr/README.md b/ipaddr/README.md similarity index 100% rename from internal/ipaddr/README.md rename to ipaddr/README.md diff --git a/internal/ipaddr/doc.go b/ipaddr/doc.go similarity index 100% rename from internal/ipaddr/doc.go rename to ipaddr/doc.go diff --git a/internal/ipaddr/ip.go b/ipaddr/ip.go similarity index 100% rename from internal/ipaddr/ip.go rename to ipaddr/ip.go diff --git a/internal/ipaddr/ip_test.go b/ipaddr/ip_test.go similarity index 100% rename from internal/ipaddr/ip_test.go rename to ipaddr/ip_test.go diff --git a/internal/ipaddr/parse.go b/ipaddr/parse.go similarity index 100% rename from internal/ipaddr/parse.go rename to ipaddr/parse.go diff --git a/internal/lang/blocktoattr/doc.go b/lang/blocktoattr/doc.go similarity index 100% rename from internal/lang/blocktoattr/doc.go rename to lang/blocktoattr/doc.go diff --git a/internal/lang/blocktoattr/fixup.go b/lang/blocktoattr/fixup.go similarity index 99% rename from internal/lang/blocktoattr/fixup.go rename to lang/blocktoattr/fixup.go index 5d05a86f2f5f..38bfda3e88dd 100644 --- a/internal/lang/blocktoattr/fixup.go +++ b/lang/blocktoattr/fixup.go @@ -5,7 +5,7 @@ import ( "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hcldec" - "github.com/hashicorp/terraform/internal/configs/configschema" + "github.com/hashicorp/terraform/configs/configschema" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/lang/blocktoattr/fixup_bench_test.go b/lang/blocktoattr/fixup_bench_test.go similarity index 97% rename from internal/lang/blocktoattr/fixup_bench_test.go rename to lang/blocktoattr/fixup_bench_test.go index 518fcfd0fb81..1515d2effdd4 100644 --- a/internal/lang/blocktoattr/fixup_bench_test.go +++ b/lang/blocktoattr/fixup_bench_test.go @@ -6,7 +6,7 @@ import ( "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hcldec" "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/hashicorp/terraform/internal/configs/configschema" + "github.com/hashicorp/terraform/configs/configschema" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/lang/blocktoattr/fixup_test.go b/lang/blocktoattr/fixup_test.go similarity index 99% rename from internal/lang/blocktoattr/fixup_test.go rename to lang/blocktoattr/fixup_test.go index 36ab48041c9a..6ab799fc3e51 100644 --- a/internal/lang/blocktoattr/fixup_test.go +++ b/lang/blocktoattr/fixup_test.go @@ -8,7 +8,7 @@ import ( "github.com/hashicorp/hcl/v2/hcldec" "github.com/hashicorp/hcl/v2/hclsyntax" hcljson "github.com/hashicorp/hcl/v2/json" - "github.com/hashicorp/terraform/internal/configs/configschema" + "github.com/hashicorp/terraform/configs/configschema" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/lang/blocktoattr/schema.go b/lang/blocktoattr/schema.go similarity index 98% rename from internal/lang/blocktoattr/schema.go rename to lang/blocktoattr/schema.go index f704a0487019..31e010cc79c5 100644 --- a/internal/lang/blocktoattr/schema.go +++ b/lang/blocktoattr/schema.go @@ -2,7 +2,7 @@ package blocktoattr import ( "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/configs/configschema" + "github.com/hashicorp/terraform/configs/configschema" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/lang/blocktoattr/variables.go b/lang/blocktoattr/variables.go similarity index 97% rename from internal/lang/blocktoattr/variables.go rename to lang/blocktoattr/variables.go index 92d593160798..ae5c609dfe4b 100644 --- a/internal/lang/blocktoattr/variables.go +++ b/lang/blocktoattr/variables.go @@ -4,7 +4,7 @@ import ( "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/ext/dynblock" "github.com/hashicorp/hcl/v2/hcldec" - "github.com/hashicorp/terraform/internal/configs/configschema" + "github.com/hashicorp/terraform/configs/configschema" ) // ExpandedVariables finds all of the global variables referenced in the diff --git a/internal/lang/blocktoattr/variables_test.go b/lang/blocktoattr/variables_test.go similarity index 98% rename from internal/lang/blocktoattr/variables_test.go rename to lang/blocktoattr/variables_test.go index 94076b75c274..0fa417142585 100644 --- a/internal/lang/blocktoattr/variables_test.go +++ b/lang/blocktoattr/variables_test.go @@ -8,7 +8,7 @@ import ( "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclsyntax" hcljson "github.com/hashicorp/hcl/v2/json" - "github.com/hashicorp/terraform/internal/configs/configschema" + "github.com/hashicorp/terraform/configs/configschema" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/lang/data.go b/lang/data.go similarity index 94% rename from internal/lang/data.go rename to lang/data.go index 710fccedc8c5..a47a2a32de20 100644 --- a/internal/lang/data.go +++ b/lang/data.go @@ -1,8 +1,8 @@ package lang import ( - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/tfdiags" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/lang/data_test.go b/lang/data_test.go similarity index 95% rename from internal/lang/data_test.go rename to lang/data_test.go index e86a8561839b..4215bdae0f1f 100644 --- a/internal/lang/data_test.go +++ b/lang/data_test.go @@ -1,8 +1,8 @@ package lang import ( - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/tfdiags" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/lang/doc.go b/lang/doc.go similarity index 100% rename from internal/lang/doc.go rename to lang/doc.go diff --git a/internal/lang/eval.go b/lang/eval.go similarity index 98% rename from internal/lang/eval.go rename to lang/eval.go index 5c82392bcc44..41e7a144f91f 100644 --- a/internal/lang/eval.go +++ b/lang/eval.go @@ -6,11 +6,11 @@ import ( "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/ext/dynblock" "github.com/hashicorp/hcl/v2/hcldec" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/instances" - "github.com/hashicorp/terraform/internal/lang/blocktoattr" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/instances" + "github.com/hashicorp/terraform/lang/blocktoattr" + "github.com/hashicorp/terraform/tfdiags" "github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty/convert" ) diff --git a/internal/lang/eval_test.go b/lang/eval_test.go similarity index 99% rename from internal/lang/eval_test.go rename to lang/eval_test.go index 37e9e54a0c08..4b812a7edac3 100644 --- a/internal/lang/eval_test.go +++ b/lang/eval_test.go @@ -5,9 +5,9 @@ import ( "encoding/json" "testing" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/instances" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/instances" "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclsyntax" diff --git a/internal/lang/funcs/cidr.go b/lang/funcs/cidr.go similarity index 99% rename from internal/lang/funcs/cidr.go rename to lang/funcs/cidr.go index bf878b50cb7a..e3b007cede58 100644 --- a/internal/lang/funcs/cidr.go +++ b/lang/funcs/cidr.go @@ -5,7 +5,7 @@ import ( "math/big" "github.com/apparentlymart/go-cidr/cidr" - "github.com/hashicorp/terraform/internal/ipaddr" + "github.com/hashicorp/terraform/ipaddr" "github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty/function" "github.com/zclconf/go-cty/cty/gocty" diff --git a/internal/lang/funcs/cidr_test.go b/lang/funcs/cidr_test.go similarity index 100% rename from internal/lang/funcs/cidr_test.go rename to lang/funcs/cidr_test.go diff --git a/internal/lang/funcs/collection.go b/lang/funcs/collection.go similarity index 100% rename from internal/lang/funcs/collection.go rename to lang/funcs/collection.go diff --git a/internal/lang/funcs/collection_test.go b/lang/funcs/collection_test.go similarity index 99% rename from internal/lang/funcs/collection_test.go rename to lang/funcs/collection_test.go index d470f357edbe..ca1f3cc0d4ea 100644 --- a/internal/lang/funcs/collection_test.go +++ b/lang/funcs/collection_test.go @@ -5,7 +5,7 @@ import ( "math" "testing" - "github.com/hashicorp/terraform/internal/lang/marks" + "github.com/hashicorp/terraform/lang/marks" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/lang/funcs/conversion.go b/lang/funcs/conversion.go similarity index 97% rename from internal/lang/funcs/conversion.go rename to lang/funcs/conversion.go index 721606226e3f..3f1ed7a32130 100644 --- a/internal/lang/funcs/conversion.go +++ b/lang/funcs/conversion.go @@ -3,8 +3,8 @@ package funcs import ( "strconv" - "github.com/hashicorp/terraform/internal/lang/marks" - "github.com/hashicorp/terraform/internal/lang/types" + "github.com/hashicorp/terraform/lang/marks" + "github.com/hashicorp/terraform/lang/types" "github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty/convert" "github.com/zclconf/go-cty/cty/function" diff --git a/internal/lang/funcs/conversion_test.go b/lang/funcs/conversion_test.go similarity index 98% rename from internal/lang/funcs/conversion_test.go rename to lang/funcs/conversion_test.go index 9c3e7e9f74ae..1cbc41c2ed42 100644 --- a/internal/lang/funcs/conversion_test.go +++ b/lang/funcs/conversion_test.go @@ -4,7 +4,7 @@ import ( "fmt" "testing" - "github.com/hashicorp/terraform/internal/lang/marks" + "github.com/hashicorp/terraform/lang/marks" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/lang/funcs/crypto.go b/lang/funcs/crypto.go similarity index 100% rename from internal/lang/funcs/crypto.go rename to lang/funcs/crypto.go diff --git a/internal/lang/funcs/crypto_test.go b/lang/funcs/crypto_test.go similarity index 100% rename from internal/lang/funcs/crypto_test.go rename to lang/funcs/crypto_test.go diff --git a/internal/lang/funcs/datetime.go b/lang/funcs/datetime.go similarity index 100% rename from internal/lang/funcs/datetime.go rename to lang/funcs/datetime.go diff --git a/internal/lang/funcs/datetime_test.go b/lang/funcs/datetime_test.go similarity index 100% rename from internal/lang/funcs/datetime_test.go rename to lang/funcs/datetime_test.go diff --git a/internal/lang/funcs/descriptions.go b/lang/funcs/descriptions.go similarity index 100% rename from internal/lang/funcs/descriptions.go rename to lang/funcs/descriptions.go diff --git a/internal/lang/funcs/encoding.go b/lang/funcs/encoding.go similarity index 100% rename from internal/lang/funcs/encoding.go rename to lang/funcs/encoding.go diff --git a/internal/lang/funcs/encoding_test.go b/lang/funcs/encoding_test.go similarity index 99% rename from internal/lang/funcs/encoding_test.go rename to lang/funcs/encoding_test.go index 2e05784e828b..cac5a8fdcc94 100644 --- a/internal/lang/funcs/encoding_test.go +++ b/lang/funcs/encoding_test.go @@ -4,7 +4,7 @@ import ( "fmt" "testing" - "github.com/hashicorp/terraform/internal/lang/marks" + "github.com/hashicorp/terraform/lang/marks" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/lang/funcs/filesystem.go b/lang/funcs/filesystem.go similarity index 100% rename from internal/lang/funcs/filesystem.go rename to lang/funcs/filesystem.go diff --git a/internal/lang/funcs/filesystem_test.go b/lang/funcs/filesystem_test.go similarity index 99% rename from internal/lang/funcs/filesystem_test.go rename to lang/funcs/filesystem_test.go index 037137ae64f4..b5caa49146bb 100644 --- a/internal/lang/funcs/filesystem_test.go +++ b/lang/funcs/filesystem_test.go @@ -6,7 +6,7 @@ import ( "path/filepath" "testing" - "github.com/hashicorp/terraform/internal/lang/marks" + "github.com/hashicorp/terraform/lang/marks" homedir "github.com/mitchellh/go-homedir" "github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty/function" diff --git a/internal/lang/funcs/number.go b/lang/funcs/number.go similarity index 100% rename from internal/lang/funcs/number.go rename to lang/funcs/number.go diff --git a/internal/lang/funcs/number_test.go b/lang/funcs/number_test.go similarity index 99% rename from internal/lang/funcs/number_test.go rename to lang/funcs/number_test.go index 6caf19af1899..6419414102f4 100644 --- a/internal/lang/funcs/number_test.go +++ b/lang/funcs/number_test.go @@ -4,7 +4,7 @@ import ( "fmt" "testing" - "github.com/hashicorp/terraform/internal/lang/marks" + "github.com/hashicorp/terraform/lang/marks" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/lang/funcs/redact.go b/lang/funcs/redact.go similarity index 87% rename from internal/lang/funcs/redact.go rename to lang/funcs/redact.go index bbec3f0a1bd1..d9fb3fc90cea 100644 --- a/internal/lang/funcs/redact.go +++ b/lang/funcs/redact.go @@ -3,7 +3,7 @@ package funcs import ( "fmt" - "github.com/hashicorp/terraform/internal/lang/marks" + "github.com/hashicorp/terraform/lang/marks" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/lang/funcs/redact_test.go b/lang/funcs/redact_test.go similarity index 95% rename from internal/lang/funcs/redact_test.go rename to lang/funcs/redact_test.go index e378d5f5afe7..f5a1c669e5d8 100644 --- a/internal/lang/funcs/redact_test.go +++ b/lang/funcs/redact_test.go @@ -3,7 +3,7 @@ package funcs import ( "testing" - "github.com/hashicorp/terraform/internal/lang/marks" + "github.com/hashicorp/terraform/lang/marks" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/lang/funcs/sensitive.go b/lang/funcs/sensitive.go similarity index 97% rename from internal/lang/funcs/sensitive.go rename to lang/funcs/sensitive.go index 1ce0774a3322..9fa65287a5e9 100644 --- a/internal/lang/funcs/sensitive.go +++ b/lang/funcs/sensitive.go @@ -1,7 +1,7 @@ package funcs import ( - "github.com/hashicorp/terraform/internal/lang/marks" + "github.com/hashicorp/terraform/lang/marks" "github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty/function" ) diff --git a/internal/lang/funcs/sensitive_test.go b/lang/funcs/sensitive_test.go similarity index 98% rename from internal/lang/funcs/sensitive_test.go rename to lang/funcs/sensitive_test.go index 2d0120e8e770..46d1627428ae 100644 --- a/internal/lang/funcs/sensitive_test.go +++ b/lang/funcs/sensitive_test.go @@ -4,7 +4,7 @@ import ( "fmt" "testing" - "github.com/hashicorp/terraform/internal/lang/marks" + "github.com/hashicorp/terraform/lang/marks" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/lang/funcs/string.go b/lang/funcs/string.go similarity index 100% rename from internal/lang/funcs/string.go rename to lang/funcs/string.go diff --git a/internal/lang/funcs/string_test.go b/lang/funcs/string_test.go similarity index 100% rename from internal/lang/funcs/string_test.go rename to lang/funcs/string_test.go diff --git a/internal/lang/funcs/testdata/bare.tmpl b/lang/funcs/testdata/bare.tmpl similarity index 100% rename from internal/lang/funcs/testdata/bare.tmpl rename to lang/funcs/testdata/bare.tmpl diff --git a/internal/lang/funcs/testdata/func.tmpl b/lang/funcs/testdata/func.tmpl similarity index 100% rename from internal/lang/funcs/testdata/func.tmpl rename to lang/funcs/testdata/func.tmpl diff --git a/internal/lang/funcs/testdata/hello.tmpl b/lang/funcs/testdata/hello.tmpl similarity index 100% rename from internal/lang/funcs/testdata/hello.tmpl rename to lang/funcs/testdata/hello.tmpl diff --git a/internal/lang/funcs/testdata/hello.txt b/lang/funcs/testdata/hello.txt similarity index 100% rename from internal/lang/funcs/testdata/hello.txt rename to lang/funcs/testdata/hello.txt diff --git a/internal/lang/funcs/testdata/icon.png b/lang/funcs/testdata/icon.png similarity index 100% rename from internal/lang/funcs/testdata/icon.png rename to lang/funcs/testdata/icon.png diff --git a/internal/lang/funcs/testdata/list.tmpl b/lang/funcs/testdata/list.tmpl similarity index 100% rename from internal/lang/funcs/testdata/list.tmpl rename to lang/funcs/testdata/list.tmpl diff --git a/internal/lang/funcs/testdata/recursive.tmpl b/lang/funcs/testdata/recursive.tmpl similarity index 100% rename from internal/lang/funcs/testdata/recursive.tmpl rename to lang/funcs/testdata/recursive.tmpl diff --git a/internal/lang/funcs/testdata/unreadable/foobar b/lang/funcs/testdata/unreadable/foobar similarity index 100% rename from internal/lang/funcs/testdata/unreadable/foobar rename to lang/funcs/testdata/unreadable/foobar diff --git a/internal/lang/functions.go b/lang/functions.go similarity index 98% rename from internal/lang/functions.go rename to lang/functions.go index 8b1c9192d1c1..fefd3d47eddb 100644 --- a/internal/lang/functions.go +++ b/lang/functions.go @@ -9,8 +9,8 @@ import ( "github.com/zclconf/go-cty/cty/function" "github.com/zclconf/go-cty/cty/function/stdlib" - "github.com/hashicorp/terraform/internal/experiments" - "github.com/hashicorp/terraform/internal/lang/funcs" + "github.com/hashicorp/terraform/experiments" + "github.com/hashicorp/terraform/lang/funcs" ) var impureFunctions = []string{ diff --git a/internal/lang/functions_descriptions_test.go b/lang/functions_descriptions_test.go similarity index 91% rename from internal/lang/functions_descriptions_test.go rename to lang/functions_descriptions_test.go index ee456d87ac3e..e179000e774b 100644 --- a/internal/lang/functions_descriptions_test.go +++ b/lang/functions_descriptions_test.go @@ -3,7 +3,7 @@ package lang import ( "testing" - "github.com/hashicorp/terraform/internal/lang/funcs" + "github.com/hashicorp/terraform/lang/funcs" ) func TestFunctionDescriptions(t *testing.T) { diff --git a/internal/lang/functions_test.go b/lang/functions_test.go similarity index 99% rename from internal/lang/functions_test.go rename to lang/functions_test.go index e6d5e1987478..4fa528f96507 100644 --- a/internal/lang/functions_test.go +++ b/lang/functions_test.go @@ -8,8 +8,8 @@ import ( "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/hashicorp/terraform/internal/experiments" - "github.com/hashicorp/terraform/internal/lang/marks" + "github.com/hashicorp/terraform/experiments" + "github.com/hashicorp/terraform/lang/marks" homedir "github.com/mitchellh/go-homedir" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/lang/globalref/analyzer.go b/lang/globalref/analyzer.go similarity index 94% rename from internal/lang/globalref/analyzer.go rename to lang/globalref/analyzer.go index 7a24d781ef39..1915302e3075 100644 --- a/internal/lang/globalref/analyzer.go +++ b/lang/globalref/analyzer.go @@ -3,9 +3,9 @@ package globalref import ( "fmt" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/providers" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/providers" ) // Analyzer is the main component of this package, serving as a container for diff --git a/internal/lang/globalref/analyzer_contributing_resources.go b/lang/globalref/analyzer_contributing_resources.go similarity index 98% rename from internal/lang/globalref/analyzer_contributing_resources.go rename to lang/globalref/analyzer_contributing_resources.go index 4024bafd0c8d..a61a8f43ad09 100644 --- a/internal/lang/globalref/analyzer_contributing_resources.go +++ b/lang/globalref/analyzer_contributing_resources.go @@ -3,7 +3,7 @@ package globalref import ( "sort" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) // ContributingResources analyzes all of the given references and diff --git a/internal/lang/globalref/analyzer_contributing_resources_test.go b/lang/globalref/analyzer_contributing_resources_test.go similarity index 99% rename from internal/lang/globalref/analyzer_contributing_resources_test.go rename to lang/globalref/analyzer_contributing_resources_test.go index 79c441c4318f..61962ec4ffaa 100644 --- a/internal/lang/globalref/analyzer_contributing_resources_test.go +++ b/lang/globalref/analyzer_contributing_resources_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) func TestAnalyzerContributingResources(t *testing.T) { diff --git a/internal/lang/globalref/analyzer_meta_references.go b/lang/globalref/analyzer_meta_references.go similarity index 99% rename from internal/lang/globalref/analyzer_meta_references.go rename to lang/globalref/analyzer_meta_references.go index 9a2bb89920bf..e717533283af 100644 --- a/internal/lang/globalref/analyzer_meta_references.go +++ b/lang/globalref/analyzer_meta_references.go @@ -2,9 +2,9 @@ package globalref import ( "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/lang" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/lang" "github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty/convert" "github.com/zclconf/go-cty/cty/gocty" diff --git a/internal/lang/globalref/analyzer_meta_references_shortcuts.go b/lang/globalref/analyzer_meta_references_shortcuts.go similarity index 96% rename from internal/lang/globalref/analyzer_meta_references_shortcuts.go rename to lang/globalref/analyzer_meta_references_shortcuts.go index 580e99b360f5..a715cb8a9102 100644 --- a/internal/lang/globalref/analyzer_meta_references_shortcuts.go +++ b/lang/globalref/analyzer_meta_references_shortcuts.go @@ -3,8 +3,8 @@ package globalref import ( "fmt" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/lang" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/lang" ) // ReferencesFromOutputValue returns all of the direct references from the diff --git a/internal/lang/globalref/analyzer_meta_references_test.go b/lang/globalref/analyzer_meta_references_test.go similarity index 98% rename from internal/lang/globalref/analyzer_meta_references_test.go rename to lang/globalref/analyzer_meta_references_test.go index c693890cf6d2..014b60b93015 100644 --- a/internal/lang/globalref/analyzer_meta_references_test.go +++ b/lang/globalref/analyzer_meta_references_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) func TestAnalyzerMetaReferences(t *testing.T) { diff --git a/internal/lang/globalref/analyzer_test.go b/lang/globalref/analyzer_test.go similarity index 88% rename from internal/lang/globalref/analyzer_test.go rename to lang/globalref/analyzer_test.go index 0a66217e7d9a..cc0de50c251e 100644 --- a/internal/lang/globalref/analyzer_test.go +++ b/lang/globalref/analyzer_test.go @@ -5,12 +5,12 @@ import ( "path/filepath" "testing" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configload" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/initwd" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/registry" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/initwd" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/registry" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/lang/globalref/doc.go b/lang/globalref/doc.go similarity index 100% rename from internal/lang/globalref/doc.go rename to lang/globalref/doc.go diff --git a/internal/lang/globalref/reference.go b/lang/globalref/reference.go similarity index 98% rename from internal/lang/globalref/reference.go rename to lang/globalref/reference.go index d47cecfa70c7..eb9b7defbba2 100644 --- a/internal/lang/globalref/reference.go +++ b/lang/globalref/reference.go @@ -4,8 +4,8 @@ import ( "fmt" "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/tfdiags" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/lang/globalref/testdata/assorted/assorted-root.tf b/lang/globalref/testdata/assorted/assorted-root.tf similarity index 100% rename from internal/lang/globalref/testdata/assorted/assorted-root.tf rename to lang/globalref/testdata/assorted/assorted-root.tf diff --git a/internal/lang/globalref/testdata/assorted/child/assorted-child.tf b/lang/globalref/testdata/assorted/child/assorted-child.tf similarity index 100% rename from internal/lang/globalref/testdata/assorted/child/assorted-child.tf rename to lang/globalref/testdata/assorted/child/assorted-child.tf diff --git a/internal/lang/globalref/testdata/contributing-resources/compute/contributing-resources-compute.tf b/lang/globalref/testdata/contributing-resources/compute/contributing-resources-compute.tf similarity index 100% rename from internal/lang/globalref/testdata/contributing-resources/compute/contributing-resources-compute.tf rename to lang/globalref/testdata/contributing-resources/compute/contributing-resources-compute.tf diff --git a/internal/lang/globalref/testdata/contributing-resources/contributing-resources-root.tf b/lang/globalref/testdata/contributing-resources/contributing-resources-root.tf similarity index 100% rename from internal/lang/globalref/testdata/contributing-resources/contributing-resources-root.tf rename to lang/globalref/testdata/contributing-resources/contributing-resources-root.tf diff --git a/internal/lang/globalref/testdata/contributing-resources/network/contributing-resources-network.tf b/lang/globalref/testdata/contributing-resources/network/contributing-resources-network.tf similarity index 100% rename from internal/lang/globalref/testdata/contributing-resources/network/contributing-resources-network.tf rename to lang/globalref/testdata/contributing-resources/network/contributing-resources-network.tf diff --git a/internal/lang/marks/marks.go b/lang/marks/marks.go similarity index 100% rename from internal/lang/marks/marks.go rename to lang/marks/marks.go diff --git a/internal/lang/references.go b/lang/references.go similarity index 92% rename from internal/lang/references.go rename to lang/references.go index 7f41b09b6173..569251cb8dfb 100644 --- a/internal/lang/references.go +++ b/lang/references.go @@ -2,10 +2,10 @@ package lang import ( "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/lang/blocktoattr" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/lang/blocktoattr" + "github.com/hashicorp/terraform/tfdiags" ) // References finds all of the references in the given set of traversals, diff --git a/internal/lang/scope.go b/lang/scope.go similarity index 94% rename from internal/lang/scope.go rename to lang/scope.go index 6c229e25d90a..3a34e9ca2a07 100644 --- a/internal/lang/scope.go +++ b/lang/scope.go @@ -5,8 +5,8 @@ import ( "github.com/zclconf/go-cty/cty/function" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/experiments" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/experiments" ) // Scope is the main type in this package, allowing dynamic evaluation of diff --git a/internal/lang/testdata/functions-test/hello.tmpl b/lang/testdata/functions-test/hello.tmpl similarity index 100% rename from internal/lang/testdata/functions-test/hello.tmpl rename to lang/testdata/functions-test/hello.tmpl diff --git a/internal/lang/testdata/functions-test/hello.txt b/lang/testdata/functions-test/hello.txt similarity index 100% rename from internal/lang/testdata/functions-test/hello.txt rename to lang/testdata/functions-test/hello.txt diff --git a/internal/lang/testdata/functions-test/subdirectory/hello.tmpl b/lang/testdata/functions-test/subdirectory/hello.tmpl similarity index 100% rename from internal/lang/testdata/functions-test/subdirectory/hello.tmpl rename to lang/testdata/functions-test/subdirectory/hello.tmpl diff --git a/internal/lang/testdata/functions-test/subdirectory/hello.txt b/lang/testdata/functions-test/subdirectory/hello.txt similarity index 100% rename from internal/lang/testdata/functions-test/subdirectory/hello.txt rename to lang/testdata/functions-test/subdirectory/hello.txt diff --git a/internal/lang/types/type_type.go b/lang/types/type_type.go similarity index 100% rename from internal/lang/types/type_type.go rename to lang/types/type_type.go diff --git a/internal/lang/types/types.go b/lang/types/types.go similarity index 100% rename from internal/lang/types/types.go rename to lang/types/types.go diff --git a/internal/legacy/helper/acctest/acctest.go b/legacy/helper/acctest/acctest.go similarity index 100% rename from internal/legacy/helper/acctest/acctest.go rename to legacy/helper/acctest/acctest.go diff --git a/internal/legacy/helper/acctest/random.go b/legacy/helper/acctest/random.go similarity index 100% rename from internal/legacy/helper/acctest/random.go rename to legacy/helper/acctest/random.go diff --git a/internal/legacy/helper/acctest/random_test.go b/legacy/helper/acctest/random_test.go similarity index 100% rename from internal/legacy/helper/acctest/random_test.go rename to legacy/helper/acctest/random_test.go diff --git a/internal/legacy/helper/acctest/remotetests.go b/legacy/helper/acctest/remotetests.go similarity index 100% rename from internal/legacy/helper/acctest/remotetests.go rename to legacy/helper/acctest/remotetests.go diff --git a/internal/legacy/helper/hashcode/hashcode.go b/legacy/helper/hashcode/hashcode.go similarity index 100% rename from internal/legacy/helper/hashcode/hashcode.go rename to legacy/helper/hashcode/hashcode.go diff --git a/internal/legacy/helper/hashcode/hashcode_test.go b/legacy/helper/hashcode/hashcode_test.go similarity index 100% rename from internal/legacy/helper/hashcode/hashcode_test.go rename to legacy/helper/hashcode/hashcode_test.go diff --git a/internal/legacy/helper/schema/backend.go b/legacy/helper/schema/backend.go similarity index 95% rename from internal/legacy/helper/schema/backend.go rename to legacy/helper/schema/backend.go index 7bd9426abea0..17cdb060cddd 100644 --- a/internal/legacy/helper/schema/backend.go +++ b/legacy/helper/schema/backend.go @@ -4,12 +4,12 @@ import ( "context" "fmt" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/configs/hcl2shim" - "github.com/hashicorp/terraform/internal/legacy/terraform" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/configs/hcl2shim" + "github.com/hashicorp/terraform/legacy/terraform" ctyconvert "github.com/zclconf/go-cty/cty/convert" ) diff --git a/internal/legacy/helper/schema/backend_test.go b/legacy/helper/schema/backend_test.go similarity index 100% rename from internal/legacy/helper/schema/backend_test.go rename to legacy/helper/schema/backend_test.go diff --git a/internal/legacy/helper/schema/core_schema.go b/legacy/helper/schema/core_schema.go similarity index 99% rename from internal/legacy/helper/schema/core_schema.go rename to legacy/helper/schema/core_schema.go index da9c502da00f..6a53db1a71a3 100644 --- a/internal/legacy/helper/schema/core_schema.go +++ b/legacy/helper/schema/core_schema.go @@ -3,7 +3,7 @@ package schema import ( "fmt" - "github.com/hashicorp/terraform/internal/configs/configschema" + "github.com/hashicorp/terraform/configs/configschema" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/legacy/helper/schema/core_schema_test.go b/legacy/helper/schema/core_schema_test.go similarity index 99% rename from internal/legacy/helper/schema/core_schema_test.go rename to legacy/helper/schema/core_schema_test.go index 84649c8bec14..7d4b32e01956 100644 --- a/internal/legacy/helper/schema/core_schema_test.go +++ b/legacy/helper/schema/core_schema_test.go @@ -7,7 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/configs/configschema" + "github.com/hashicorp/terraform/configs/configschema" ) // add the implicit "id" attribute for test resources diff --git a/internal/legacy/helper/schema/data_source_resource_shim.go b/legacy/helper/schema/data_source_resource_shim.go similarity index 100% rename from internal/legacy/helper/schema/data_source_resource_shim.go rename to legacy/helper/schema/data_source_resource_shim.go diff --git a/internal/legacy/helper/schema/doc.go b/legacy/helper/schema/doc.go similarity index 100% rename from internal/legacy/helper/schema/doc.go rename to legacy/helper/schema/doc.go diff --git a/internal/legacy/helper/schema/equal.go b/legacy/helper/schema/equal.go similarity index 100% rename from internal/legacy/helper/schema/equal.go rename to legacy/helper/schema/equal.go diff --git a/internal/legacy/helper/schema/field_reader.go b/legacy/helper/schema/field_reader.go similarity index 100% rename from internal/legacy/helper/schema/field_reader.go rename to legacy/helper/schema/field_reader.go diff --git a/internal/legacy/helper/schema/field_reader_config.go b/legacy/helper/schema/field_reader_config.go similarity index 99% rename from internal/legacy/helper/schema/field_reader_config.go rename to legacy/helper/schema/field_reader_config.go index f4a43d1fce43..6509e48a6769 100644 --- a/internal/legacy/helper/schema/field_reader_config.go +++ b/legacy/helper/schema/field_reader_config.go @@ -7,7 +7,7 @@ import ( "strings" "sync" - "github.com/hashicorp/terraform/internal/legacy/terraform" + "github.com/hashicorp/terraform/legacy/terraform" "github.com/mitchellh/mapstructure" ) diff --git a/internal/legacy/helper/schema/field_reader_config_test.go b/legacy/helper/schema/field_reader_config_test.go similarity index 98% rename from internal/legacy/helper/schema/field_reader_config_test.go rename to legacy/helper/schema/field_reader_config_test.go index 7a22f3ce1687..6dfc20566a90 100644 --- a/internal/legacy/helper/schema/field_reader_config_test.go +++ b/legacy/helper/schema/field_reader_config_test.go @@ -6,9 +6,9 @@ import ( "reflect" "testing" - "github.com/hashicorp/terraform/internal/configs/hcl2shim" - "github.com/hashicorp/terraform/internal/legacy/helper/hashcode" - "github.com/hashicorp/terraform/internal/legacy/terraform" + "github.com/hashicorp/terraform/configs/hcl2shim" + "github.com/hashicorp/terraform/legacy/helper/hashcode" + "github.com/hashicorp/terraform/legacy/terraform" ) func TestConfigFieldReader_impl(t *testing.T) { diff --git a/internal/legacy/helper/schema/field_reader_diff.go b/legacy/helper/schema/field_reader_diff.go similarity index 99% rename from internal/legacy/helper/schema/field_reader_diff.go rename to legacy/helper/schema/field_reader_diff.go index 84ebe272e073..ec9fa2887c3d 100644 --- a/internal/legacy/helper/schema/field_reader_diff.go +++ b/legacy/helper/schema/field_reader_diff.go @@ -4,7 +4,7 @@ import ( "fmt" "strings" - "github.com/hashicorp/terraform/internal/legacy/terraform" + "github.com/hashicorp/terraform/legacy/terraform" "github.com/mitchellh/mapstructure" ) diff --git a/internal/legacy/helper/schema/field_reader_diff_test.go b/legacy/helper/schema/field_reader_diff_test.go similarity index 99% rename from internal/legacy/helper/schema/field_reader_diff_test.go rename to legacy/helper/schema/field_reader_diff_test.go index 1f6fa7da1743..77f387619c25 100644 --- a/internal/legacy/helper/schema/field_reader_diff_test.go +++ b/legacy/helper/schema/field_reader_diff_test.go @@ -4,7 +4,7 @@ import ( "reflect" "testing" - "github.com/hashicorp/terraform/internal/legacy/terraform" + "github.com/hashicorp/terraform/legacy/terraform" ) func TestDiffFieldReader_impl(t *testing.T) { diff --git a/internal/legacy/helper/schema/field_reader_map.go b/legacy/helper/schema/field_reader_map.go similarity index 100% rename from internal/legacy/helper/schema/field_reader_map.go rename to legacy/helper/schema/field_reader_map.go diff --git a/internal/legacy/helper/schema/field_reader_map_test.go b/legacy/helper/schema/field_reader_map_test.go similarity index 100% rename from internal/legacy/helper/schema/field_reader_map_test.go rename to legacy/helper/schema/field_reader_map_test.go diff --git a/internal/legacy/helper/schema/field_reader_multi.go b/legacy/helper/schema/field_reader_multi.go similarity index 100% rename from internal/legacy/helper/schema/field_reader_multi.go rename to legacy/helper/schema/field_reader_multi.go diff --git a/internal/legacy/helper/schema/field_reader_multi_test.go b/legacy/helper/schema/field_reader_multi_test.go similarity index 98% rename from internal/legacy/helper/schema/field_reader_multi_test.go rename to legacy/helper/schema/field_reader_multi_test.go index 7410335f68db..cc2c808fc79a 100644 --- a/internal/legacy/helper/schema/field_reader_multi_test.go +++ b/legacy/helper/schema/field_reader_multi_test.go @@ -5,7 +5,7 @@ import ( "strconv" "testing" - "github.com/hashicorp/terraform/internal/legacy/terraform" + "github.com/hashicorp/terraform/legacy/terraform" ) func TestMultiLevelFieldReaderReadFieldExact(t *testing.T) { diff --git a/internal/legacy/helper/schema/field_reader_test.go b/legacy/helper/schema/field_reader_test.go similarity index 100% rename from internal/legacy/helper/schema/field_reader_test.go rename to legacy/helper/schema/field_reader_test.go diff --git a/internal/legacy/helper/schema/field_writer.go b/legacy/helper/schema/field_writer.go similarity index 100% rename from internal/legacy/helper/schema/field_writer.go rename to legacy/helper/schema/field_writer.go diff --git a/internal/legacy/helper/schema/field_writer_map.go b/legacy/helper/schema/field_writer_map.go similarity index 100% rename from internal/legacy/helper/schema/field_writer_map.go rename to legacy/helper/schema/field_writer_map.go diff --git a/internal/legacy/helper/schema/field_writer_map_test.go b/legacy/helper/schema/field_writer_map_test.go similarity index 100% rename from internal/legacy/helper/schema/field_writer_map_test.go rename to legacy/helper/schema/field_writer_map_test.go diff --git a/internal/legacy/helper/schema/getsource_string.go b/legacy/helper/schema/getsource_string.go similarity index 100% rename from internal/legacy/helper/schema/getsource_string.go rename to legacy/helper/schema/getsource_string.go diff --git a/internal/legacy/helper/schema/provider.go b/legacy/helper/schema/provider.go similarity index 99% rename from internal/legacy/helper/schema/provider.go rename to legacy/helper/schema/provider.go index c64c2e38278c..a4cb879b4c1c 100644 --- a/internal/legacy/helper/schema/provider.go +++ b/legacy/helper/schema/provider.go @@ -8,8 +8,8 @@ import ( "sync" multierror "github.com/hashicorp/go-multierror" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/legacy/terraform" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/legacy/terraform" ) var ReservedProviderFields = []string{ diff --git a/internal/legacy/helper/schema/provider_test.go b/legacy/helper/schema/provider_test.go similarity index 98% rename from internal/legacy/helper/schema/provider_test.go rename to legacy/helper/schema/provider_test.go index 1b176bc0d259..7b9bd62c01b3 100644 --- a/internal/legacy/helper/schema/provider_test.go +++ b/legacy/helper/schema/provider_test.go @@ -10,8 +10,8 @@ import ( "github.com/google/go-cmp/cmp" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/legacy/terraform" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/legacy/terraform" ) func TestProvider_impl(t *testing.T) { diff --git a/internal/legacy/helper/schema/provisioner.go b/legacy/helper/schema/provisioner.go similarity index 97% rename from internal/legacy/helper/schema/provisioner.go rename to legacy/helper/schema/provisioner.go index 5c2cce2b0bf5..dd745001eee5 100644 --- a/internal/legacy/helper/schema/provisioner.go +++ b/legacy/helper/schema/provisioner.go @@ -7,8 +7,8 @@ import ( "sync" "github.com/hashicorp/go-multierror" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/legacy/terraform" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/legacy/terraform" ) // Provisioner represents a resource provisioner in Terraform and properly diff --git a/internal/legacy/helper/schema/provisioner_test.go b/legacy/helper/schema/provisioner_test.go similarity index 99% rename from internal/legacy/helper/schema/provisioner_test.go rename to legacy/helper/schema/provisioner_test.go index 228dacd72c62..36e5c51ad193 100644 --- a/internal/legacy/helper/schema/provisioner_test.go +++ b/legacy/helper/schema/provisioner_test.go @@ -7,7 +7,7 @@ import ( "testing" "time" - "github.com/hashicorp/terraform/internal/legacy/terraform" + "github.com/hashicorp/terraform/legacy/terraform" ) func TestProvisioner_impl(t *testing.T) { diff --git a/internal/legacy/helper/schema/resource.go b/legacy/helper/schema/resource.go similarity index 99% rename from internal/legacy/helper/schema/resource.go rename to legacy/helper/schema/resource.go index 28fa54e38c61..fd14bb7c8e49 100644 --- a/internal/legacy/helper/schema/resource.go +++ b/legacy/helper/schema/resource.go @@ -6,7 +6,7 @@ import ( "log" "strconv" - "github.com/hashicorp/terraform/internal/legacy/terraform" + "github.com/hashicorp/terraform/legacy/terraform" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/legacy/helper/schema/resource_data.go b/legacy/helper/schema/resource_data.go similarity index 99% rename from internal/legacy/helper/schema/resource_data.go rename to legacy/helper/schema/resource_data.go index 3a61e3493218..8ec64248a9cc 100644 --- a/internal/legacy/helper/schema/resource_data.go +++ b/legacy/helper/schema/resource_data.go @@ -7,7 +7,7 @@ import ( "sync" "time" - "github.com/hashicorp/terraform/internal/legacy/terraform" + "github.com/hashicorp/terraform/legacy/terraform" "github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty/gocty" ) diff --git a/internal/legacy/helper/schema/resource_data_get_source.go b/legacy/helper/schema/resource_data_get_source.go similarity index 100% rename from internal/legacy/helper/schema/resource_data_get_source.go rename to legacy/helper/schema/resource_data_get_source.go diff --git a/internal/legacy/helper/schema/resource_data_test.go b/legacy/helper/schema/resource_data_test.go similarity index 99% rename from internal/legacy/helper/schema/resource_data_test.go rename to legacy/helper/schema/resource_data_test.go index 22ad45b6b82b..bfe1387ae6a9 100644 --- a/internal/legacy/helper/schema/resource_data_test.go +++ b/legacy/helper/schema/resource_data_test.go @@ -8,7 +8,7 @@ import ( "testing" "time" - "github.com/hashicorp/terraform/internal/legacy/terraform" + "github.com/hashicorp/terraform/legacy/terraform" ) func TestResourceDataGet(t *testing.T) { diff --git a/internal/legacy/helper/schema/resource_diff.go b/legacy/helper/schema/resource_diff.go similarity index 99% rename from internal/legacy/helper/schema/resource_diff.go rename to legacy/helper/schema/resource_diff.go index 72d4711eb22b..bd9103a87d17 100644 --- a/internal/legacy/helper/schema/resource_diff.go +++ b/legacy/helper/schema/resource_diff.go @@ -7,7 +7,7 @@ import ( "strings" "sync" - "github.com/hashicorp/terraform/internal/legacy/terraform" + "github.com/hashicorp/terraform/legacy/terraform" ) // newValueWriter is a minor re-implementation of MapFieldWriter to include diff --git a/internal/legacy/helper/schema/resource_diff_test.go b/legacy/helper/schema/resource_diff_test.go similarity index 99% rename from internal/legacy/helper/schema/resource_diff_test.go rename to legacy/helper/schema/resource_diff_test.go index 9737177147af..ca9f046aa4f6 100644 --- a/internal/legacy/helper/schema/resource_diff_test.go +++ b/legacy/helper/schema/resource_diff_test.go @@ -7,8 +7,8 @@ import ( "testing" "github.com/davecgh/go-spew/spew" - "github.com/hashicorp/terraform/internal/configs/hcl2shim" - "github.com/hashicorp/terraform/internal/legacy/terraform" + "github.com/hashicorp/terraform/configs/hcl2shim" + "github.com/hashicorp/terraform/legacy/terraform" ) // testSetFunc is a very simple function we use to test a foo/bar complex set. diff --git a/internal/legacy/helper/schema/resource_importer.go b/legacy/helper/schema/resource_importer.go similarity index 100% rename from internal/legacy/helper/schema/resource_importer.go rename to legacy/helper/schema/resource_importer.go diff --git a/internal/legacy/helper/schema/resource_test.go b/legacy/helper/schema/resource_test.go similarity index 99% rename from internal/legacy/helper/schema/resource_test.go rename to legacy/helper/schema/resource_test.go index 47f508d81b70..2b3a7e157531 100644 --- a/internal/legacy/helper/schema/resource_test.go +++ b/legacy/helper/schema/resource_test.go @@ -9,8 +9,8 @@ import ( "time" "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/configs/hcl2shim" - "github.com/hashicorp/terraform/internal/legacy/terraform" + "github.com/hashicorp/terraform/configs/hcl2shim" + "github.com/hashicorp/terraform/legacy/terraform" "github.com/zclconf/go-cty/cty" ctyjson "github.com/zclconf/go-cty/cty/json" diff --git a/internal/legacy/helper/schema/resource_timeout.go b/legacy/helper/schema/resource_timeout.go similarity index 98% rename from internal/legacy/helper/schema/resource_timeout.go rename to legacy/helper/schema/resource_timeout.go index df033d4c4557..9e3c5b437e98 100644 --- a/internal/legacy/helper/schema/resource_timeout.go +++ b/legacy/helper/schema/resource_timeout.go @@ -5,8 +5,8 @@ import ( "log" "time" - "github.com/hashicorp/terraform/internal/configs/hcl2shim" - "github.com/hashicorp/terraform/internal/legacy/terraform" + "github.com/hashicorp/terraform/configs/hcl2shim" + "github.com/hashicorp/terraform/legacy/terraform" "github.com/mitchellh/copystructure" ) diff --git a/internal/legacy/helper/schema/resource_timeout_test.go b/legacy/helper/schema/resource_timeout_test.go similarity index 99% rename from internal/legacy/helper/schema/resource_timeout_test.go rename to legacy/helper/schema/resource_timeout_test.go index f5091755b481..c6f2a326632f 100644 --- a/internal/legacy/helper/schema/resource_timeout_test.go +++ b/legacy/helper/schema/resource_timeout_test.go @@ -6,7 +6,7 @@ import ( "testing" "time" - "github.com/hashicorp/terraform/internal/legacy/terraform" + "github.com/hashicorp/terraform/legacy/terraform" ) func TestResourceTimeout_ConfigDecode_badkey(t *testing.T) { diff --git a/internal/legacy/helper/schema/schema.go b/legacy/helper/schema/schema.go similarity index 99% rename from internal/legacy/helper/schema/schema.go rename to legacy/helper/schema/schema.go index 99657c466071..5077ecfd89c7 100644 --- a/internal/legacy/helper/schema/schema.go +++ b/legacy/helper/schema/schema.go @@ -22,8 +22,8 @@ import ( "strings" "sync" - "github.com/hashicorp/terraform/internal/configs/hcl2shim" - "github.com/hashicorp/terraform/internal/legacy/terraform" + "github.com/hashicorp/terraform/configs/hcl2shim" + "github.com/hashicorp/terraform/legacy/terraform" "github.com/mitchellh/copystructure" "github.com/mitchellh/mapstructure" ) diff --git a/internal/legacy/helper/schema/schema_test.go b/legacy/helper/schema/schema_test.go similarity index 99% rename from internal/legacy/helper/schema/schema_test.go rename to legacy/helper/schema/schema_test.go index dcc2008e72fd..02158f1cbe49 100644 --- a/internal/legacy/helper/schema/schema_test.go +++ b/legacy/helper/schema/schema_test.go @@ -11,9 +11,9 @@ import ( "strings" "testing" - "github.com/hashicorp/terraform/internal/configs/hcl2shim" - "github.com/hashicorp/terraform/internal/legacy/helper/hashcode" - "github.com/hashicorp/terraform/internal/legacy/terraform" + "github.com/hashicorp/terraform/configs/hcl2shim" + "github.com/hashicorp/terraform/legacy/helper/hashcode" + "github.com/hashicorp/terraform/legacy/terraform" ) func TestEnvDefaultFunc(t *testing.T) { diff --git a/internal/legacy/helper/schema/serialize.go b/legacy/helper/schema/serialize.go similarity index 100% rename from internal/legacy/helper/schema/serialize.go rename to legacy/helper/schema/serialize.go diff --git a/internal/legacy/helper/schema/serialize_test.go b/legacy/helper/schema/serialize_test.go similarity index 100% rename from internal/legacy/helper/schema/serialize_test.go rename to legacy/helper/schema/serialize_test.go diff --git a/internal/legacy/helper/schema/set.go b/legacy/helper/schema/set.go similarity index 98% rename from internal/legacy/helper/schema/set.go rename to legacy/helper/schema/set.go index b44035c7c58f..df2693dcbfb6 100644 --- a/internal/legacy/helper/schema/set.go +++ b/legacy/helper/schema/set.go @@ -8,7 +8,7 @@ import ( "strconv" "sync" - "github.com/hashicorp/terraform/internal/legacy/helper/hashcode" + "github.com/hashicorp/terraform/legacy/helper/hashcode" ) // HashString hashes strings. If you want a Set of strings, this is the diff --git a/internal/legacy/helper/schema/set_test.go b/legacy/helper/schema/set_test.go similarity index 100% rename from internal/legacy/helper/schema/set_test.go rename to legacy/helper/schema/set_test.go diff --git a/internal/legacy/helper/schema/shims.go b/legacy/helper/schema/shims.go similarity index 95% rename from internal/legacy/helper/schema/shims.go rename to legacy/helper/schema/shims.go index 3f9e2e9ffbb8..64ac729e68a6 100644 --- a/internal/legacy/helper/schema/shims.go +++ b/legacy/helper/schema/shims.go @@ -6,9 +6,9 @@ import ( "github.com/zclconf/go-cty/cty" ctyjson "github.com/zclconf/go-cty/cty/json" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/configs/hcl2shim" - "github.com/hashicorp/terraform/internal/legacy/terraform" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/configs/hcl2shim" + "github.com/hashicorp/terraform/legacy/terraform" ) // DiffFromValues takes the current state and desired state as cty.Values and diff --git a/internal/legacy/helper/schema/shims_test.go b/legacy/helper/schema/shims_test.go similarity index 99% rename from internal/legacy/helper/schema/shims_test.go rename to legacy/helper/schema/shims_test.go index 91e24069ddfa..f2c31a3c17c4 100644 --- a/internal/legacy/helper/schema/shims_test.go +++ b/legacy/helper/schema/shims_test.go @@ -11,12 +11,12 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/configs/hcl2shim" - "github.com/hashicorp/terraform/internal/legacy/helper/hashcode" - "github.com/hashicorp/terraform/internal/legacy/terraform" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/configs/hcl2shim" + "github.com/hashicorp/terraform/legacy/helper/hashcode" + "github.com/hashicorp/terraform/legacy/terraform" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/tfdiags" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/legacy/helper/schema/testing.go b/legacy/helper/schema/testing.go similarity index 89% rename from internal/legacy/helper/schema/testing.go rename to legacy/helper/schema/testing.go index 3b328a87c451..2e62efd61181 100644 --- a/internal/legacy/helper/schema/testing.go +++ b/legacy/helper/schema/testing.go @@ -3,7 +3,7 @@ package schema import ( "testing" - "github.com/hashicorp/terraform/internal/legacy/terraform" + "github.com/hashicorp/terraform/legacy/terraform" ) // TestResourceDataRaw creates a ResourceData from a raw configuration map. diff --git a/internal/legacy/helper/schema/valuetype.go b/legacy/helper/schema/valuetype.go similarity index 100% rename from internal/legacy/helper/schema/valuetype.go rename to legacy/helper/schema/valuetype.go diff --git a/internal/legacy/helper/schema/valuetype_string.go b/legacy/helper/schema/valuetype_string.go similarity index 100% rename from internal/legacy/helper/schema/valuetype_string.go rename to legacy/helper/schema/valuetype_string.go diff --git a/internal/legacy/terraform/context_components.go b/legacy/terraform/context_components.go similarity index 91% rename from internal/legacy/terraform/context_components.go rename to legacy/terraform/context_components.go index 31494efb2faf..c893a16b4823 100644 --- a/internal/legacy/terraform/context_components.go +++ b/legacy/terraform/context_components.go @@ -3,9 +3,9 @@ package terraform import ( "fmt" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/provisioners" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/provisioners" ) // contextComponentFactory is the interface that Context uses diff --git a/internal/legacy/terraform/diff.go b/legacy/terraform/diff.go similarity index 99% rename from internal/legacy/terraform/diff.go rename to legacy/terraform/diff.go index 77bea3258906..4e834204d22c 100644 --- a/internal/legacy/terraform/diff.go +++ b/legacy/terraform/diff.go @@ -12,9 +12,9 @@ import ( "strings" "sync" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/configs/hcl2shim" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/configs/hcl2shim" "github.com/zclconf/go-cty/cty" "github.com/mitchellh/copystructure" diff --git a/internal/legacy/terraform/diff_test.go b/legacy/terraform/diff_test.go similarity index 99% rename from internal/legacy/terraform/diff_test.go rename to legacy/terraform/diff_test.go index 5388eb44eb6b..e7ee0d818542 100644 --- a/internal/legacy/terraform/diff_test.go +++ b/legacy/terraform/diff_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) func TestDiffEmpty(t *testing.T) { diff --git a/internal/legacy/terraform/features.go b/legacy/terraform/features.go similarity index 100% rename from internal/legacy/terraform/features.go rename to legacy/terraform/features.go diff --git a/internal/legacy/terraform/instancetype.go b/legacy/terraform/instancetype.go similarity index 100% rename from internal/legacy/terraform/instancetype.go rename to legacy/terraform/instancetype.go diff --git a/internal/legacy/terraform/instancetype_string.go b/legacy/terraform/instancetype_string.go similarity index 100% rename from internal/legacy/terraform/instancetype_string.go rename to legacy/terraform/instancetype_string.go diff --git a/internal/legacy/terraform/provider_mock.go b/legacy/terraform/provider_mock.go similarity index 98% rename from internal/legacy/terraform/provider_mock.go rename to legacy/terraform/provider_mock.go index abdba432460e..9603e4377961 100644 --- a/internal/legacy/terraform/provider_mock.go +++ b/legacy/terraform/provider_mock.go @@ -7,8 +7,8 @@ import ( "github.com/zclconf/go-cty/cty" ctyjson "github.com/zclconf/go-cty/cty/json" - "github.com/hashicorp/terraform/internal/configs/hcl2shim" - "github.com/hashicorp/terraform/internal/providers" + "github.com/hashicorp/terraform/configs/hcl2shim" + "github.com/hashicorp/terraform/providers" ) var _ providers.Interface = (*MockProvider)(nil) diff --git a/internal/legacy/terraform/provisioner_mock.go b/legacy/terraform/provisioner_mock.go similarity index 98% rename from internal/legacy/terraform/provisioner_mock.go rename to legacy/terraform/provisioner_mock.go index fe76157a2daf..2a33235411f8 100644 --- a/internal/legacy/terraform/provisioner_mock.go +++ b/legacy/terraform/provisioner_mock.go @@ -3,7 +3,7 @@ package terraform import ( "sync" - "github.com/hashicorp/terraform/internal/provisioners" + "github.com/hashicorp/terraform/provisioners" ) var _ provisioners.Interface = (*MockProvisioner)(nil) diff --git a/internal/legacy/terraform/resource.go b/legacy/terraform/resource.go similarity index 98% rename from internal/legacy/terraform/resource.go rename to legacy/terraform/resource.go index ddec8f828a31..6273c8ace081 100644 --- a/internal/legacy/terraform/resource.go +++ b/legacy/terraform/resource.go @@ -11,9 +11,9 @@ import ( "github.com/mitchellh/reflectwalk" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/configs/hcl2shim" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/configs/hcl2shim" ) // Resource is a legacy way to identify a particular resource instance. diff --git a/internal/legacy/terraform/resource_address.go b/legacy/terraform/resource_address.go similarity index 99% rename from internal/legacy/terraform/resource_address.go rename to legacy/terraform/resource_address.go index 9ab24f9db56d..5f3ea4f8c340 100644 --- a/internal/legacy/terraform/resource_address.go +++ b/legacy/terraform/resource_address.go @@ -7,8 +7,8 @@ import ( "strconv" "strings" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs" ) // ResourceAddress is a way of identifying an individual resource (or, diff --git a/internal/legacy/terraform/resource_address_test.go b/legacy/terraform/resource_address_test.go similarity index 99% rename from internal/legacy/terraform/resource_address_test.go rename to legacy/terraform/resource_address_test.go index e0e8ed0061be..3bb5f2082d24 100644 --- a/internal/legacy/terraform/resource_address_test.go +++ b/legacy/terraform/resource_address_test.go @@ -5,8 +5,8 @@ import ( "reflect" "testing" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs" ) func TestParseResourceAddressInternal(t *testing.T) { diff --git a/internal/legacy/terraform/resource_mode.go b/legacy/terraform/resource_mode.go similarity index 100% rename from internal/legacy/terraform/resource_mode.go rename to legacy/terraform/resource_mode.go diff --git a/internal/legacy/terraform/resource_mode_string.go b/legacy/terraform/resource_mode_string.go similarity index 100% rename from internal/legacy/terraform/resource_mode_string.go rename to legacy/terraform/resource_mode_string.go diff --git a/internal/legacy/terraform/resource_provider.go b/legacy/terraform/resource_provider.go similarity index 100% rename from internal/legacy/terraform/resource_provider.go rename to legacy/terraform/resource_provider.go diff --git a/internal/legacy/terraform/resource_provider_mock.go b/legacy/terraform/resource_provider_mock.go similarity index 100% rename from internal/legacy/terraform/resource_provider_mock.go rename to legacy/terraform/resource_provider_mock.go diff --git a/internal/legacy/terraform/resource_provisioner.go b/legacy/terraform/resource_provisioner.go similarity index 96% rename from internal/legacy/terraform/resource_provisioner.go rename to legacy/terraform/resource_provisioner.go index 647693a9fa52..d5f707880362 100644 --- a/internal/legacy/terraform/resource_provisioner.go +++ b/legacy/terraform/resource_provisioner.go @@ -1,8 +1,8 @@ package terraform import ( - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/provisioners" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/provisioners" ) // ResourceProvisioner is an interface that must be implemented by any diff --git a/internal/legacy/terraform/resource_provisioner_mock.go b/legacy/terraform/resource_provisioner_mock.go similarity index 96% rename from internal/legacy/terraform/resource_provisioner_mock.go rename to legacy/terraform/resource_provisioner_mock.go index 27c07b7dc6b2..7b88cf733391 100644 --- a/internal/legacy/terraform/resource_provisioner_mock.go +++ b/legacy/terraform/resource_provisioner_mock.go @@ -3,7 +3,7 @@ package terraform import ( "sync" - "github.com/hashicorp/terraform/internal/configs/configschema" + "github.com/hashicorp/terraform/configs/configschema" ) // MockResourceProvisioner implements ResourceProvisioner but mocks out all the diff --git a/internal/legacy/terraform/resource_test.go b/legacy/terraform/resource_test.go similarity index 99% rename from internal/legacy/terraform/resource_test.go rename to legacy/terraform/resource_test.go index c91c70c1c6e1..835163c4a2ae 100644 --- a/internal/legacy/terraform/resource_test.go +++ b/legacy/terraform/resource_test.go @@ -5,10 +5,10 @@ import ( "reflect" "testing" - "github.com/hashicorp/terraform/internal/configs/configschema" + "github.com/hashicorp/terraform/configs/configschema" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/configs/hcl2shim" + "github.com/hashicorp/terraform/configs/hcl2shim" "github.com/mitchellh/reflectwalk" ) diff --git a/internal/legacy/terraform/schemas.go b/legacy/terraform/schemas.go similarity index 96% rename from internal/legacy/terraform/schemas.go rename to legacy/terraform/schemas.go index 20b77ea9734a..0044606536bf 100644 --- a/internal/legacy/terraform/schemas.go +++ b/legacy/terraform/schemas.go @@ -4,12 +4,12 @@ import ( "fmt" "log" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/tfdiags" ) // Schemas is a container for various kinds of schema that Terraform needs diff --git a/internal/legacy/terraform/state.go b/legacy/terraform/state.go similarity index 99% rename from internal/legacy/terraform/state.go rename to legacy/terraform/state.go index 4d68ac956e87..73b916404942 100644 --- a/internal/legacy/terraform/state.go +++ b/legacy/terraform/state.go @@ -22,12 +22,12 @@ import ( version "github.com/hashicorp/go-version" "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/configs/hcl2shim" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/configs/hcl2shim" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/tfdiags" tfversion "github.com/hashicorp/terraform/version" "github.com/mitchellh/copystructure" "github.com/zclconf/go-cty/cty" diff --git a/internal/legacy/terraform/state_filter.go b/legacy/terraform/state_filter.go similarity index 100% rename from internal/legacy/terraform/state_filter.go rename to legacy/terraform/state_filter.go diff --git a/internal/legacy/terraform/state_test.go b/legacy/terraform/state_test.go similarity index 99% rename from internal/legacy/terraform/state_test.go rename to legacy/terraform/state_test.go index 1edbfb6912fd..beac79705266 100644 --- a/internal/legacy/terraform/state_test.go +++ b/legacy/terraform/state_test.go @@ -11,8 +11,8 @@ import ( "testing" "github.com/davecgh/go-spew/spew" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/hcl2shim" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs/hcl2shim" ) func TestStateValidate(t *testing.T) { diff --git a/internal/legacy/terraform/state_upgrade_v1_to_v2.go b/legacy/terraform/state_upgrade_v1_to_v2.go similarity index 100% rename from internal/legacy/terraform/state_upgrade_v1_to_v2.go rename to legacy/terraform/state_upgrade_v1_to_v2.go diff --git a/internal/legacy/terraform/state_upgrade_v2_to_v3.go b/legacy/terraform/state_upgrade_v2_to_v3.go similarity index 100% rename from internal/legacy/terraform/state_upgrade_v2_to_v3.go rename to legacy/terraform/state_upgrade_v2_to_v3.go diff --git a/internal/legacy/terraform/state_v1.go b/legacy/terraform/state_v1.go similarity index 100% rename from internal/legacy/terraform/state_v1.go rename to legacy/terraform/state_v1.go diff --git a/internal/legacy/terraform/testing.go b/legacy/terraform/testing.go similarity index 100% rename from internal/legacy/terraform/testing.go rename to legacy/terraform/testing.go diff --git a/internal/legacy/terraform/ui_input.go b/legacy/terraform/ui_input.go similarity index 100% rename from internal/legacy/terraform/ui_input.go rename to legacy/terraform/ui_input.go diff --git a/internal/legacy/terraform/ui_input_mock.go b/legacy/terraform/ui_input_mock.go similarity index 100% rename from internal/legacy/terraform/ui_input_mock.go rename to legacy/terraform/ui_input_mock.go diff --git a/internal/legacy/terraform/ui_input_prefix.go b/legacy/terraform/ui_input_prefix.go similarity index 100% rename from internal/legacy/terraform/ui_input_prefix.go rename to legacy/terraform/ui_input_prefix.go diff --git a/internal/legacy/terraform/ui_input_prefix_test.go b/legacy/terraform/ui_input_prefix_test.go similarity index 100% rename from internal/legacy/terraform/ui_input_prefix_test.go rename to legacy/terraform/ui_input_prefix_test.go diff --git a/internal/legacy/terraform/ui_output.go b/legacy/terraform/ui_output.go similarity index 100% rename from internal/legacy/terraform/ui_output.go rename to legacy/terraform/ui_output.go diff --git a/internal/legacy/terraform/ui_output_callback.go b/legacy/terraform/ui_output_callback.go similarity index 100% rename from internal/legacy/terraform/ui_output_callback.go rename to legacy/terraform/ui_output_callback.go diff --git a/internal/legacy/terraform/ui_output_callback_test.go b/legacy/terraform/ui_output_callback_test.go similarity index 100% rename from internal/legacy/terraform/ui_output_callback_test.go rename to legacy/terraform/ui_output_callback_test.go diff --git a/internal/legacy/terraform/ui_output_mock.go b/legacy/terraform/ui_output_mock.go similarity index 100% rename from internal/legacy/terraform/ui_output_mock.go rename to legacy/terraform/ui_output_mock.go diff --git a/internal/legacy/terraform/ui_output_mock_test.go b/legacy/terraform/ui_output_mock_test.go similarity index 100% rename from internal/legacy/terraform/ui_output_mock_test.go rename to legacy/terraform/ui_output_mock_test.go diff --git a/internal/legacy/terraform/upgrade_state_v1_test.go b/legacy/terraform/upgrade_state_v1_test.go similarity index 100% rename from internal/legacy/terraform/upgrade_state_v1_test.go rename to legacy/terraform/upgrade_state_v1_test.go diff --git a/internal/legacy/terraform/upgrade_state_v2_test.go b/legacy/terraform/upgrade_state_v2_test.go similarity index 100% rename from internal/legacy/terraform/upgrade_state_v2_test.go rename to legacy/terraform/upgrade_state_v2_test.go diff --git a/internal/legacy/terraform/util.go b/legacy/terraform/util.go similarity index 100% rename from internal/legacy/terraform/util.go rename to legacy/terraform/util.go diff --git a/internal/legacy/terraform/util_test.go b/legacy/terraform/util_test.go similarity index 100% rename from internal/legacy/terraform/util_test.go rename to legacy/terraform/util_test.go diff --git a/internal/legacy/terraform/version.go b/legacy/terraform/version.go similarity index 100% rename from internal/legacy/terraform/version.go rename to legacy/terraform/version.go diff --git a/internal/legacy/terraform/version_required.go b/legacy/terraform/version_required.go similarity index 95% rename from internal/legacy/terraform/version_required.go rename to legacy/terraform/version_required.go index f14d93f681d3..4c9cb34a4133 100644 --- a/internal/legacy/terraform/version_required.go +++ b/legacy/terraform/version_required.go @@ -4,9 +4,9 @@ import ( "fmt" "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" - "github.com/hashicorp/terraform/internal/configs" + "github.com/hashicorp/terraform/configs" tfversion "github.com/hashicorp/terraform/version" ) diff --git a/internal/logging/indent.go b/logging/indent.go similarity index 100% rename from internal/logging/indent.go rename to logging/indent.go diff --git a/internal/logging/indent_test.go b/logging/indent_test.go similarity index 100% rename from internal/logging/indent_test.go rename to logging/indent_test.go diff --git a/internal/logging/logging.go b/logging/logging.go similarity index 100% rename from internal/logging/logging.go rename to logging/logging.go diff --git a/internal/logging/panic.go b/logging/panic.go similarity index 100% rename from internal/logging/panic.go rename to logging/panic.go diff --git a/internal/logging/panic_test.go b/logging/panic_test.go similarity index 100% rename from internal/logging/panic_test.go rename to logging/panic_test.go diff --git a/main.go b/main.go index c807bb5a40da..385e05b7829a 100644 --- a/main.go +++ b/main.go @@ -12,19 +12,19 @@ import ( "github.com/hashicorp/go-plugin" "github.com/hashicorp/terraform-svchost/disco" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/command/cliconfig" - "github.com/hashicorp/terraform/internal/command/format" - "github.com/hashicorp/terraform/internal/didyoumean" - "github.com/hashicorp/terraform/internal/httpclient" - "github.com/hashicorp/terraform/internal/logging" - "github.com/hashicorp/terraform/internal/terminal" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/command/cliconfig" + "github.com/hashicorp/terraform/command/format" + "github.com/hashicorp/terraform/didyoumean" + "github.com/hashicorp/terraform/httpclient" + "github.com/hashicorp/terraform/logging" + "github.com/hashicorp/terraform/terminal" "github.com/hashicorp/terraform/version" "github.com/mattn/go-shellwords" "github.com/mitchellh/cli" "github.com/mitchellh/colorstring" - backendInit "github.com/hashicorp/terraform/internal/backend/init" + backendInit "github.com/hashicorp/terraform/backend/init" ) const ( diff --git a/internal/modsdir/doc.go b/modsdir/doc.go similarity index 100% rename from internal/modsdir/doc.go rename to modsdir/doc.go diff --git a/internal/modsdir/manifest.go b/modsdir/manifest.go similarity index 99% rename from internal/modsdir/manifest.go rename to modsdir/manifest.go index fbb35919cc79..c72b220889c6 100644 --- a/internal/modsdir/manifest.go +++ b/modsdir/manifest.go @@ -13,7 +13,7 @@ import ( version "github.com/hashicorp/go-version" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) // Record represents some metadata about an installed module, as part diff --git a/internal/modsdir/paths.go b/modsdir/paths.go similarity index 100% rename from internal/modsdir/paths.go rename to modsdir/paths.go diff --git a/internal/moduledeps/dependencies.go b/moduledeps/dependencies.go similarity index 93% rename from internal/moduledeps/dependencies.go rename to moduledeps/dependencies.go index 6de7aff0ba59..dd21a0a2555f 100644 --- a/internal/moduledeps/dependencies.go +++ b/moduledeps/dependencies.go @@ -1,8 +1,8 @@ package moduledeps import ( - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/plugin/discovery" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/plugin/discovery" ) // Providers describes a set of provider dependencies for a given module. diff --git a/internal/moduledeps/doc.go b/moduledeps/doc.go similarity index 100% rename from internal/moduledeps/doc.go rename to moduledeps/doc.go diff --git a/internal/moduledeps/module.go b/moduledeps/module.go similarity index 99% rename from internal/moduledeps/module.go rename to moduledeps/module.go index e428a4ec4152..4db9b3f20576 100644 --- a/internal/moduledeps/module.go +++ b/moduledeps/module.go @@ -4,7 +4,7 @@ import ( "sort" "strings" - "github.com/hashicorp/terraform/internal/plugin/discovery" + "github.com/hashicorp/terraform/plugin/discovery" ) // Module represents the dependencies of a single module, as well being diff --git a/internal/moduledeps/module_test.go b/moduledeps/module_test.go similarity index 97% rename from internal/moduledeps/module_test.go rename to moduledeps/module_test.go index dfbc99d219d5..d835e526750a 100644 --- a/internal/moduledeps/module_test.go +++ b/moduledeps/module_test.go @@ -5,8 +5,8 @@ import ( "reflect" "testing" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/plugin/discovery" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/plugin/discovery" ) func TestModuleWalkTree(t *testing.T) { diff --git a/internal/moduletest/assertion.go b/moduletest/assertion.go similarity index 97% rename from internal/moduletest/assertion.go rename to moduletest/assertion.go index 1bacbfac92b4..007772ed6cec 100644 --- a/internal/moduletest/assertion.go +++ b/moduletest/assertion.go @@ -1,7 +1,7 @@ package moduletest import ( - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" ) // Assertion is the description of a single test assertion, whether diff --git a/internal/moduletest/doc.go b/moduletest/doc.go similarity index 100% rename from internal/moduletest/doc.go rename to moduletest/doc.go diff --git a/internal/moduletest/provider.go b/moduletest/provider.go similarity index 99% rename from internal/moduletest/provider.go rename to moduletest/provider.go index 52601d9d280f..bd40893fd642 100644 --- a/internal/moduletest/provider.go +++ b/moduletest/provider.go @@ -10,10 +10,10 @@ import ( ctyjson "github.com/zclconf/go-cty/cty/json" "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/repl" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/repl" + "github.com/hashicorp/terraform/tfdiags" ) // Provider is an implementation of providers.Interface which we're diff --git a/internal/moduletest/provider_test.go b/moduletest/provider_test.go similarity index 98% rename from internal/moduletest/provider_test.go rename to moduletest/provider_test.go index 30ca0359a64f..33891c534262 100644 --- a/internal/moduletest/provider_test.go +++ b/moduletest/provider_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/providers" + "github.com/hashicorp/terraform/providers" "github.com/zclconf/go-cty-debug/ctydebug" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/moduletest/status_string.go b/moduletest/status_string.go similarity index 100% rename from internal/moduletest/status_string.go rename to moduletest/status_string.go diff --git a/internal/moduletest/suite.go b/moduletest/suite.go similarity index 100% rename from internal/moduletest/suite.go rename to moduletest/suite.go diff --git a/internal/plans/action.go b/plans/action.go similarity index 100% rename from internal/plans/action.go rename to plans/action.go diff --git a/internal/plans/action_string.go b/plans/action_string.go similarity index 100% rename from internal/plans/action_string.go rename to plans/action_string.go diff --git a/internal/plans/changes.go b/plans/changes.go similarity index 99% rename from internal/plans/changes.go rename to plans/changes.go index 7c54928331e6..0fa7309ef628 100644 --- a/internal/plans/changes.go +++ b/plans/changes.go @@ -3,8 +3,8 @@ package plans import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/states" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/states" ) // Changes describes various actions that Terraform will attempt to take if diff --git a/internal/plans/changes_src.go b/plans/changes_src.go similarity index 98% rename from internal/plans/changes_src.go rename to plans/changes_src.go index 396493956771..37462350f8fa 100644 --- a/internal/plans/changes_src.go +++ b/plans/changes_src.go @@ -3,8 +3,8 @@ package plans import ( "fmt" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/states" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/states" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/plans/changes_state.go b/plans/changes_state.go similarity index 90% rename from internal/plans/changes_state.go rename to plans/changes_state.go index 8446e9be66c8..543e6c2bd89d 100644 --- a/internal/plans/changes_state.go +++ b/plans/changes_state.go @@ -1,7 +1,7 @@ package plans import ( - "github.com/hashicorp/terraform/internal/states" + "github.com/hashicorp/terraform/states" ) // PlannedState merges the set of changes described by the receiver into the diff --git a/internal/plans/changes_sync.go b/plans/changes_sync.go similarity index 98% rename from internal/plans/changes_sync.go rename to plans/changes_sync.go index 2b4254b04494..fae09145d1d1 100644 --- a/internal/plans/changes_sync.go +++ b/plans/changes_sync.go @@ -4,8 +4,8 @@ import ( "fmt" "sync" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/states" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/states" ) // ChangesSync is a wrapper around a Changes that provides a concurrency-safe diff --git a/internal/plans/changes_test.go b/plans/changes_test.go similarity index 97% rename from internal/plans/changes_test.go rename to plans/changes_test.go index 5dbe10f08a93..110119389373 100644 --- a/internal/plans/changes_test.go +++ b/plans/changes_test.go @@ -4,8 +4,8 @@ import ( "fmt" "testing" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/lang/marks" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/lang/marks" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/plans/doc.go b/plans/doc.go similarity index 100% rename from internal/plans/doc.go rename to plans/doc.go diff --git a/internal/plans/dynamic_value.go b/plans/dynamic_value.go similarity index 100% rename from internal/plans/dynamic_value.go rename to plans/dynamic_value.go diff --git a/internal/plans/internal/planproto/doc.go b/plans/internal/planproto/doc.go similarity index 100% rename from internal/plans/internal/planproto/doc.go rename to plans/internal/planproto/doc.go diff --git a/internal/plans/internal/planproto/planfile.pb.go b/plans/internal/planproto/planfile.pb.go similarity index 100% rename from internal/plans/internal/planproto/planfile.pb.go rename to plans/internal/planproto/planfile.pb.go diff --git a/internal/plans/internal/planproto/planfile.proto b/plans/internal/planproto/planfile.proto similarity index 100% rename from internal/plans/internal/planproto/planfile.proto rename to plans/internal/planproto/planfile.proto diff --git a/internal/plans/mode.go b/plans/mode.go similarity index 100% rename from internal/plans/mode.go rename to plans/mode.go diff --git a/internal/plans/mode_string.go b/plans/mode_string.go similarity index 100% rename from internal/plans/mode_string.go rename to plans/mode_string.go diff --git a/internal/plans/objchange/action.go b/plans/objchange/action.go similarity index 96% rename from internal/plans/objchange/action.go rename to plans/objchange/action.go index 56418aaee81a..2ca32097cf78 100644 --- a/internal/plans/objchange/action.go +++ b/plans/objchange/action.go @@ -3,7 +3,7 @@ package objchange import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/plans" ) // ActionForChange determines which plans.Action value best describes a diff --git a/internal/plans/objchange/compatible.go b/plans/objchange/compatible.go similarity index 99% rename from internal/plans/objchange/compatible.go rename to plans/objchange/compatible.go index ca5026380115..8ead63fa0af6 100644 --- a/internal/plans/objchange/compatible.go +++ b/plans/objchange/compatible.go @@ -7,8 +7,8 @@ import ( "github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty/convert" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/lang/marks" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/lang/marks" ) // AssertObjectCompatible checks whether the given "actual" value is a valid diff --git a/internal/plans/objchange/compatible_test.go b/plans/objchange/compatible_test.go similarity index 99% rename from internal/plans/objchange/compatible_test.go rename to plans/objchange/compatible_test.go index 213d3e103fb9..65390345a7b9 100644 --- a/internal/plans/objchange/compatible_test.go +++ b/plans/objchange/compatible_test.go @@ -7,9 +7,9 @@ import ( "github.com/apparentlymart/go-dump/dump" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/lang/marks" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/lang/marks" + "github.com/hashicorp/terraform/tfdiags" ) func TestAssertObjectCompatible(t *testing.T) { diff --git a/internal/plans/objchange/doc.go b/plans/objchange/doc.go similarity index 100% rename from internal/plans/objchange/doc.go rename to plans/objchange/doc.go diff --git a/internal/plans/objchange/lcs.go b/plans/objchange/lcs.go similarity index 100% rename from internal/plans/objchange/lcs.go rename to plans/objchange/lcs.go diff --git a/internal/plans/objchange/lcs_test.go b/plans/objchange/lcs_test.go similarity index 98% rename from internal/plans/objchange/lcs_test.go rename to plans/objchange/lcs_test.go index ea31ac226f59..5af7e7c950f9 100644 --- a/internal/plans/objchange/lcs_test.go +++ b/plans/objchange/lcs_test.go @@ -4,7 +4,7 @@ import ( "fmt" "testing" - "github.com/hashicorp/terraform/internal/lang/marks" + "github.com/hashicorp/terraform/lang/marks" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/plans/objchange/normalize_obj.go b/plans/objchange/normalize_obj.go similarity index 98% rename from internal/plans/objchange/normalize_obj.go rename to plans/objchange/normalize_obj.go index 3db3f66f58c3..47229b4748d2 100644 --- a/internal/plans/objchange/normalize_obj.go +++ b/plans/objchange/normalize_obj.go @@ -1,7 +1,7 @@ package objchange import ( - "github.com/hashicorp/terraform/internal/configs/configschema" + "github.com/hashicorp/terraform/configs/configschema" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/plans/objchange/normalize_obj_test.go b/plans/objchange/normalize_obj_test.go similarity index 99% rename from internal/plans/objchange/normalize_obj_test.go rename to plans/objchange/normalize_obj_test.go index e350e181c48f..abc9c3770971 100644 --- a/internal/plans/objchange/normalize_obj_test.go +++ b/plans/objchange/normalize_obj_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/apparentlymart/go-dump/dump" - "github.com/hashicorp/terraform/internal/configs/configschema" + "github.com/hashicorp/terraform/configs/configschema" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/plans/objchange/objchange.go b/plans/objchange/objchange.go similarity index 99% rename from internal/plans/objchange/objchange.go rename to plans/objchange/objchange.go index 88f044edac65..44b83ce58cad 100644 --- a/internal/plans/objchange/objchange.go +++ b/plans/objchange/objchange.go @@ -6,7 +6,7 @@ import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/configs/configschema" + "github.com/hashicorp/terraform/configs/configschema" ) // ProposedNew constructs a proposed new object value by combining the diff --git a/internal/plans/objchange/objchange_test.go b/plans/objchange/objchange_test.go similarity index 99% rename from internal/plans/objchange/objchange_test.go rename to plans/objchange/objchange_test.go index 27b79d5379c4..99b20b99ebd1 100644 --- a/internal/plans/objchange/objchange_test.go +++ b/plans/objchange/objchange_test.go @@ -6,7 +6,7 @@ import ( "github.com/apparentlymart/go-dump/dump" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/configs/configschema" + "github.com/hashicorp/terraform/configs/configschema" ) func TestProposedNew(t *testing.T) { diff --git a/internal/plans/objchange/plan_valid.go b/plans/objchange/plan_valid.go similarity index 99% rename from internal/plans/objchange/plan_valid.go rename to plans/objchange/plan_valid.go index 305bc10b18f9..b9c22ce490a3 100644 --- a/internal/plans/objchange/plan_valid.go +++ b/plans/objchange/plan_valid.go @@ -5,7 +5,7 @@ import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/configs/configschema" + "github.com/hashicorp/terraform/configs/configschema" ) // AssertPlanValid checks checks whether a planned new state returned by a diff --git a/internal/plans/objchange/plan_valid_test.go b/plans/objchange/plan_valid_test.go similarity index 99% rename from internal/plans/objchange/plan_valid_test.go rename to plans/objchange/plan_valid_test.go index 00a1602ac2bc..714751a28a77 100644 --- a/internal/plans/objchange/plan_valid_test.go +++ b/plans/objchange/plan_valid_test.go @@ -6,8 +6,8 @@ import ( "github.com/apparentlymart/go-dump/dump" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/tfdiags" ) func TestAssertPlanValid(t *testing.T) { diff --git a/internal/plans/plan.go b/plans/plan.go similarity index 97% rename from internal/plans/plan.go rename to plans/plan.go index 4ac924d010b7..469901caa5a7 100644 --- a/internal/plans/plan.go +++ b/plans/plan.go @@ -3,10 +3,10 @@ package plans import ( "sort" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/lang/globalref" - "github.com/hashicorp/terraform/internal/states" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/lang/globalref" + "github.com/hashicorp/terraform/states" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/plans/plan_test.go b/plans/plan_test.go similarity index 97% rename from internal/plans/plan_test.go rename to plans/plan_test.go index 34f9361394f9..b8a0e4501ba0 100644 --- a/internal/plans/plan_test.go +++ b/plans/plan_test.go @@ -5,7 +5,7 @@ import ( "github.com/go-test/deep" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) func TestProviderAddrs(t *testing.T) { diff --git a/internal/plans/planfile/config_snapshot.go b/plans/planfile/config_snapshot.go similarity index 99% rename from internal/plans/planfile/config_snapshot.go rename to plans/planfile/config_snapshot.go index 163366d9bcf9..a78a99b31fce 100644 --- a/internal/plans/planfile/config_snapshot.go +++ b/plans/planfile/config_snapshot.go @@ -11,7 +11,7 @@ import ( "time" version "github.com/hashicorp/go-version" - "github.com/hashicorp/terraform/internal/configs/configload" + "github.com/hashicorp/terraform/configs/configload" ) const configSnapshotPrefix = "tfconfig/" diff --git a/internal/plans/planfile/config_snapshot_test.go b/plans/planfile/config_snapshot_test.go similarity index 94% rename from internal/plans/planfile/config_snapshot_test.go rename to plans/planfile/config_snapshot_test.go index 91069ea38c77..2efd0031f66c 100644 --- a/internal/plans/planfile/config_snapshot_test.go +++ b/plans/planfile/config_snapshot_test.go @@ -9,7 +9,7 @@ import ( "github.com/davecgh/go-spew/spew" - "github.com/hashicorp/terraform/internal/configs/configload" + "github.com/hashicorp/terraform/configs/configload" ) func TestConfigSnapshotRoundtrip(t *testing.T) { diff --git a/internal/plans/planfile/doc.go b/plans/planfile/doc.go similarity index 100% rename from internal/plans/planfile/doc.go rename to plans/planfile/doc.go diff --git a/internal/plans/planfile/planfile_test.go b/plans/planfile/planfile_test.go similarity index 92% rename from internal/plans/planfile/planfile_test.go rename to plans/planfile/planfile_test.go index af3615cfcf90..767b608733f0 100644 --- a/internal/plans/planfile/planfile_test.go +++ b/plans/planfile/planfile_test.go @@ -6,13 +6,13 @@ import ( "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configload" - "github.com/hashicorp/terraform/internal/depsfile" - "github.com/hashicorp/terraform/internal/getproviders" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/statefile" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/depsfile" + "github.com/hashicorp/terraform/getproviders" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/statefile" tfversion "github.com/hashicorp/terraform/version" ) diff --git a/internal/plans/planfile/reader.go b/plans/planfile/reader.go similarity index 96% rename from internal/plans/planfile/reader.go rename to plans/planfile/reader.go index ff6e129e0bac..d37546836257 100644 --- a/internal/plans/planfile/reader.go +++ b/plans/planfile/reader.go @@ -6,12 +6,12 @@ import ( "fmt" "io/ioutil" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configload" - "github.com/hashicorp/terraform/internal/depsfile" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states/statefile" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/depsfile" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/states/statefile" + "github.com/hashicorp/terraform/tfdiags" ) const tfstateFilename = "tfstate" diff --git a/internal/plans/planfile/testdata/test-config/.terraform/modules/child_a/child_a.tf b/plans/planfile/testdata/test-config/.terraform/modules/child_a/child_a.tf similarity index 100% rename from internal/plans/planfile/testdata/test-config/.terraform/modules/child_a/child_a.tf rename to plans/planfile/testdata/test-config/.terraform/modules/child_a/child_a.tf diff --git a/internal/plans/planfile/testdata/test-config/.terraform/modules/child_a/child_c/child_c.tf b/plans/planfile/testdata/test-config/.terraform/modules/child_a/child_c/child_c.tf similarity index 100% rename from internal/plans/planfile/testdata/test-config/.terraform/modules/child_a/child_c/child_c.tf rename to plans/planfile/testdata/test-config/.terraform/modules/child_a/child_c/child_c.tf diff --git a/internal/plans/planfile/testdata/test-config/.terraform/modules/child_b.child_d/child_d.tf b/plans/planfile/testdata/test-config/.terraform/modules/child_b.child_d/child_d.tf similarity index 100% rename from internal/plans/planfile/testdata/test-config/.terraform/modules/child_b.child_d/child_d.tf rename to plans/planfile/testdata/test-config/.terraform/modules/child_b.child_d/child_d.tf diff --git a/internal/plans/planfile/testdata/test-config/.terraform/modules/child_b/child_b.tf b/plans/planfile/testdata/test-config/.terraform/modules/child_b/child_b.tf similarity index 100% rename from internal/plans/planfile/testdata/test-config/.terraform/modules/child_b/child_b.tf rename to plans/planfile/testdata/test-config/.terraform/modules/child_b/child_b.tf diff --git a/internal/plans/planfile/testdata/test-config/.terraform/modules/modules.json b/plans/planfile/testdata/test-config/.terraform/modules/modules.json similarity index 100% rename from internal/plans/planfile/testdata/test-config/.terraform/modules/modules.json rename to plans/planfile/testdata/test-config/.terraform/modules/modules.json diff --git a/internal/plans/planfile/testdata/test-config/root.tf b/plans/planfile/testdata/test-config/root.tf similarity index 100% rename from internal/plans/planfile/testdata/test-config/root.tf rename to plans/planfile/testdata/test-config/root.tf diff --git a/internal/plans/planfile/tfplan.go b/plans/planfile/tfplan.go similarity index 98% rename from internal/plans/planfile/tfplan.go rename to plans/planfile/tfplan.go index 19866b6714e9..6cea17568fa4 100644 --- a/internal/plans/planfile/tfplan.go +++ b/plans/planfile/tfplan.go @@ -7,13 +7,13 @@ import ( "google.golang.org/protobuf/proto" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/checks" - "github.com/hashicorp/terraform/internal/lang/globalref" - "github.com/hashicorp/terraform/internal/lang/marks" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/plans/internal/planproto" - "github.com/hashicorp/terraform/internal/states" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/checks" + "github.com/hashicorp/terraform/lang/globalref" + "github.com/hashicorp/terraform/lang/marks" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/plans/internal/planproto" + "github.com/hashicorp/terraform/states" "github.com/hashicorp/terraform/version" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/plans/planfile/tfplan_test.go b/plans/planfile/tfplan_test.go similarity index 96% rename from internal/plans/planfile/tfplan_test.go rename to plans/planfile/tfplan_test.go index 6984ceafdcad..68e1481dd201 100644 --- a/internal/plans/planfile/tfplan_test.go +++ b/plans/planfile/tfplan_test.go @@ -7,12 +7,12 @@ import ( "github.com/go-test/deep" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/checks" - "github.com/hashicorp/terraform/internal/lang/globalref" - "github.com/hashicorp/terraform/internal/lang/marks" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/checks" + "github.com/hashicorp/terraform/lang/globalref" + "github.com/hashicorp/terraform/lang/marks" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/states" ) func TestTFPlanRoundTrip(t *testing.T) { diff --git a/internal/plans/planfile/writer.go b/plans/planfile/writer.go similarity index 94% rename from internal/plans/planfile/writer.go rename to plans/planfile/writer.go index bdf84c86db44..a33ee24b6e41 100644 --- a/internal/plans/planfile/writer.go +++ b/plans/planfile/writer.go @@ -6,10 +6,10 @@ import ( "os" "time" - "github.com/hashicorp/terraform/internal/configs/configload" - "github.com/hashicorp/terraform/internal/depsfile" - "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states/statefile" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/depsfile" + "github.com/hashicorp/terraform/plans" + "github.com/hashicorp/terraform/states/statefile" ) type CreateArgs struct { diff --git a/internal/plans/resourceinstancechangeactionreason_string.go b/plans/resourceinstancechangeactionreason_string.go similarity index 100% rename from internal/plans/resourceinstancechangeactionreason_string.go rename to plans/resourceinstancechangeactionreason_string.go diff --git a/internal/plugin/convert/diagnostics.go b/plugin/convert/diagnostics.go similarity index 97% rename from internal/plugin/convert/diagnostics.go rename to plugin/convert/diagnostics.go index 43824e1b797e..8aa9e0fb9b77 100644 --- a/internal/plugin/convert/diagnostics.go +++ b/plugin/convert/diagnostics.go @@ -1,8 +1,8 @@ package convert import ( - "github.com/hashicorp/terraform/internal/tfdiags" - proto "github.com/hashicorp/terraform/internal/tfplugin5" + "github.com/hashicorp/terraform/tfdiags" + proto "github.com/hashicorp/terraform/tfplugin5" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/plugin/convert/diagnostics_test.go b/plugin/convert/diagnostics_test.go similarity index 98% rename from internal/plugin/convert/diagnostics_test.go rename to plugin/convert/diagnostics_test.go index 3f54985dd5ea..d700ab699d3e 100644 --- a/internal/plugin/convert/diagnostics_test.go +++ b/plugin/convert/diagnostics_test.go @@ -8,8 +8,8 @@ import ( "github.com/google/go-cmp/cmp/cmpopts" "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/hashicorp/terraform/internal/tfdiags" - proto "github.com/hashicorp/terraform/internal/tfplugin5" + "github.com/hashicorp/terraform/tfdiags" + proto "github.com/hashicorp/terraform/tfplugin5" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/plugin/convert/schema.go b/plugin/convert/schema.go similarity index 96% rename from internal/plugin/convert/schema.go rename to plugin/convert/schema.go index 4a3f909935d5..65d0f14b7c68 100644 --- a/internal/plugin/convert/schema.go +++ b/plugin/convert/schema.go @@ -5,9 +5,9 @@ import ( "reflect" "sort" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/providers" - proto "github.com/hashicorp/terraform/internal/tfplugin5" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/providers" + proto "github.com/hashicorp/terraform/tfplugin5" ) // ConfigSchemaToProto takes a *configschema.Block and converts it to a diff --git a/internal/plugin/convert/schema_test.go b/plugin/convert/schema_test.go similarity index 98% rename from internal/plugin/convert/schema_test.go rename to plugin/convert/schema_test.go index 4df254fb765f..0464cf15d5f6 100644 --- a/internal/plugin/convert/schema_test.go +++ b/plugin/convert/schema_test.go @@ -5,8 +5,8 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - "github.com/hashicorp/terraform/internal/configs/configschema" - proto "github.com/hashicorp/terraform/internal/tfplugin5" + "github.com/hashicorp/terraform/configs/configschema" + proto "github.com/hashicorp/terraform/tfplugin5" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/plugin/discovery/find.go b/plugin/discovery/find.go similarity index 100% rename from internal/plugin/discovery/find.go rename to plugin/discovery/find.go diff --git a/internal/plugin/discovery/find_test.go b/plugin/discovery/find_test.go similarity index 100% rename from internal/plugin/discovery/find_test.go rename to plugin/discovery/find_test.go diff --git a/internal/plugin/discovery/get_cache.go b/plugin/discovery/get_cache.go similarity index 100% rename from internal/plugin/discovery/get_cache.go rename to plugin/discovery/get_cache.go diff --git a/internal/plugin/discovery/get_cache_test.go b/plugin/discovery/get_cache_test.go similarity index 100% rename from internal/plugin/discovery/get_cache_test.go rename to plugin/discovery/get_cache_test.go diff --git a/internal/plugin/discovery/meta.go b/plugin/discovery/meta.go similarity index 100% rename from internal/plugin/discovery/meta.go rename to plugin/discovery/meta.go diff --git a/internal/plugin/discovery/meta_set.go b/plugin/discovery/meta_set.go similarity index 100% rename from internal/plugin/discovery/meta_set.go rename to plugin/discovery/meta_set.go diff --git a/internal/plugin/discovery/meta_set_test.go b/plugin/discovery/meta_set_test.go similarity index 100% rename from internal/plugin/discovery/meta_set_test.go rename to plugin/discovery/meta_set_test.go diff --git a/internal/plugin/discovery/meta_test.go b/plugin/discovery/meta_test.go similarity index 100% rename from internal/plugin/discovery/meta_test.go rename to plugin/discovery/meta_test.go diff --git a/internal/plugin/discovery/requirements.go b/plugin/discovery/requirements.go similarity index 100% rename from internal/plugin/discovery/requirements.go rename to plugin/discovery/requirements.go diff --git a/internal/plugin/discovery/requirements_test.go b/plugin/discovery/requirements_test.go similarity index 100% rename from internal/plugin/discovery/requirements_test.go rename to plugin/discovery/requirements_test.go diff --git a/internal/plugin/discovery/testdata/current-style-plugins/mockos_mockarch/terraform-foo-bar_v0.0.1 b/plugin/discovery/testdata/current-style-plugins/mockos_mockarch/terraform-foo-bar_v0.0.1 similarity index 100% rename from internal/plugin/discovery/testdata/current-style-plugins/mockos_mockarch/terraform-foo-bar_v0.0.1 rename to plugin/discovery/testdata/current-style-plugins/mockos_mockarch/terraform-foo-bar_v0.0.1 diff --git a/internal/plugin/discovery/testdata/current-style-plugins/mockos_mockarch/terraform-foo-missing-version b/plugin/discovery/testdata/current-style-plugins/mockos_mockarch/terraform-foo-missing-version similarity index 100% rename from internal/plugin/discovery/testdata/current-style-plugins/mockos_mockarch/terraform-foo-missing-version rename to plugin/discovery/testdata/current-style-plugins/mockos_mockarch/terraform-foo-missing-version diff --git a/internal/plugin/discovery/testdata/current-style-plugins/mockos_mockarch/terraform-notfoo-bar_v0.0.1 b/plugin/discovery/testdata/current-style-plugins/mockos_mockarch/terraform-notfoo-bar_v0.0.1 similarity index 100% rename from internal/plugin/discovery/testdata/current-style-plugins/mockos_mockarch/terraform-notfoo-bar_v0.0.1 rename to plugin/discovery/testdata/current-style-plugins/mockos_mockarch/terraform-notfoo-bar_v0.0.1 diff --git a/internal/plugin/discovery/testdata/legacy-style-plugins/terraform-foo-bar b/plugin/discovery/testdata/legacy-style-plugins/terraform-foo-bar similarity index 100% rename from internal/plugin/discovery/testdata/legacy-style-plugins/terraform-foo-bar rename to plugin/discovery/testdata/legacy-style-plugins/terraform-foo-bar diff --git a/internal/plugin/discovery/testdata/legacy-style-plugins/terraform-foo-baz b/plugin/discovery/testdata/legacy-style-plugins/terraform-foo-baz similarity index 100% rename from internal/plugin/discovery/testdata/legacy-style-plugins/terraform-foo-baz rename to plugin/discovery/testdata/legacy-style-plugins/terraform-foo-baz diff --git a/internal/plugin/discovery/testdata/legacy-style-plugins/terraform-notfoo-bar b/plugin/discovery/testdata/legacy-style-plugins/terraform-notfoo-bar similarity index 100% rename from internal/plugin/discovery/testdata/legacy-style-plugins/terraform-notfoo-bar rename to plugin/discovery/testdata/legacy-style-plugins/terraform-notfoo-bar diff --git a/internal/plugin/discovery/testdata/not-a-dir b/plugin/discovery/testdata/not-a-dir similarity index 100% rename from internal/plugin/discovery/testdata/not-a-dir rename to plugin/discovery/testdata/not-a-dir diff --git a/internal/plugin/discovery/testdata/plugin-cache/terraform-provider-foo_v0.0.1_x4 b/plugin/discovery/testdata/plugin-cache/terraform-provider-foo_v0.0.1_x4 similarity index 100% rename from internal/plugin/discovery/testdata/plugin-cache/terraform-provider-foo_v0.0.1_x4 rename to plugin/discovery/testdata/plugin-cache/terraform-provider-foo_v0.0.1_x4 diff --git a/internal/plugin/discovery/version.go b/plugin/discovery/version.go similarity index 100% rename from internal/plugin/discovery/version.go rename to plugin/discovery/version.go diff --git a/internal/plugin/discovery/version_set.go b/plugin/discovery/version_set.go similarity index 100% rename from internal/plugin/discovery/version_set.go rename to plugin/discovery/version_set.go diff --git a/internal/plugin/discovery/version_set_test.go b/plugin/discovery/version_set_test.go similarity index 100% rename from internal/plugin/discovery/version_set_test.go rename to plugin/discovery/version_set_test.go diff --git a/internal/plugin/discovery/version_test.go b/plugin/discovery/version_test.go similarity index 100% rename from internal/plugin/discovery/version_test.go rename to plugin/discovery/version_test.go diff --git a/internal/plugin/grpc_error.go b/plugin/grpc_error.go similarity index 97% rename from internal/plugin/grpc_error.go rename to plugin/grpc_error.go index 0f638b7fa455..99ce8c8b8d68 100644 --- a/internal/plugin/grpc_error.go +++ b/plugin/grpc_error.go @@ -5,7 +5,7 @@ import ( "path" "runtime" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) diff --git a/internal/plugin/grpc_provider.go b/plugin/grpc_provider.go similarity index 98% rename from internal/plugin/grpc_provider.go rename to plugin/grpc_provider.go index 2c4f2c036027..a909952ebad3 100644 --- a/internal/plugin/grpc_provider.go +++ b/plugin/grpc_provider.go @@ -9,10 +9,10 @@ import ( "github.com/zclconf/go-cty/cty" plugin "github.com/hashicorp/go-plugin" - "github.com/hashicorp/terraform/internal/logging" - "github.com/hashicorp/terraform/internal/plugin/convert" - "github.com/hashicorp/terraform/internal/providers" - proto "github.com/hashicorp/terraform/internal/tfplugin5" + "github.com/hashicorp/terraform/logging" + "github.com/hashicorp/terraform/plugin/convert" + "github.com/hashicorp/terraform/providers" + proto "github.com/hashicorp/terraform/tfplugin5" ctyjson "github.com/zclconf/go-cty/cty/json" "github.com/zclconf/go-cty/cty/msgpack" "google.golang.org/grpc" diff --git a/internal/plugin/grpc_provider_test.go b/plugin/grpc_provider_test.go similarity index 98% rename from internal/plugin/grpc_provider_test.go rename to plugin/grpc_provider_test.go index 4e8d2f6c9207..9f02af341a8a 100644 --- a/internal/plugin/grpc_provider_test.go +++ b/plugin/grpc_provider_test.go @@ -7,13 +7,13 @@ import ( "github.com/golang/mock/gomock" "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/configs/hcl2shim" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/configs/hcl2shim" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/tfdiags" "github.com/zclconf/go-cty/cty" - mockproto "github.com/hashicorp/terraform/internal/plugin/mock_proto" - proto "github.com/hashicorp/terraform/internal/tfplugin5" + mockproto "github.com/hashicorp/terraform/plugin/mock_proto" + proto "github.com/hashicorp/terraform/tfplugin5" ) var _ providers.Interface = (*GRPCProvider)(nil) diff --git a/internal/plugin/grpc_provisioner.go b/plugin/grpc_provisioner.go similarity index 95% rename from internal/plugin/grpc_provisioner.go rename to plugin/grpc_provisioner.go index 0a6ad8e632cc..d73214348813 100644 --- a/internal/plugin/grpc_provisioner.go +++ b/plugin/grpc_provisioner.go @@ -7,10 +7,10 @@ import ( "sync" plugin "github.com/hashicorp/go-plugin" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/plugin/convert" - "github.com/hashicorp/terraform/internal/provisioners" - proto "github.com/hashicorp/terraform/internal/tfplugin5" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/plugin/convert" + "github.com/hashicorp/terraform/provisioners" + proto "github.com/hashicorp/terraform/tfplugin5" "github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty/msgpack" "google.golang.org/grpc" diff --git a/internal/plugin/grpc_provisioner_test.go b/plugin/grpc_provisioner_test.go similarity index 92% rename from internal/plugin/grpc_provisioner_test.go rename to plugin/grpc_provisioner_test.go index 848c9460fa43..dc128f10eda2 100644 --- a/internal/plugin/grpc_provisioner_test.go +++ b/plugin/grpc_provisioner_test.go @@ -7,12 +7,12 @@ import ( "github.com/golang/mock/gomock" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - "github.com/hashicorp/terraform/internal/configs/hcl2shim" - "github.com/hashicorp/terraform/internal/provisioners" - proto "github.com/hashicorp/terraform/internal/tfplugin5" + "github.com/hashicorp/terraform/configs/hcl2shim" + "github.com/hashicorp/terraform/provisioners" + proto "github.com/hashicorp/terraform/tfplugin5" "github.com/zclconf/go-cty/cty" - mockproto "github.com/hashicorp/terraform/internal/plugin/mock_proto" + mockproto "github.com/hashicorp/terraform/plugin/mock_proto" ) var _ provisioners.Interface = (*GRPCProvisioner)(nil) diff --git a/plugin/mock_proto/generate.go b/plugin/mock_proto/generate.go new file mode 100644 index 000000000000..8490530d128c --- /dev/null +++ b/plugin/mock_proto/generate.go @@ -0,0 +1,3 @@ +//go:generate go run github.com/golang/mock/mockgen -destination mock.go github.com/hashicorp/terraform/tfplugin5 ProviderClient,ProvisionerClient,Provisioner_ProvisionResourceClient,Provisioner_ProvisionResourceServer + +package mock_tfplugin5 diff --git a/internal/plugin/mock_proto/mock.go b/plugin/mock_proto/mock.go similarity index 99% rename from internal/plugin/mock_proto/mock.go rename to plugin/mock_proto/mock.go index 054fe1cd821a..b91153789933 100644 --- a/internal/plugin/mock_proto/mock.go +++ b/plugin/mock_proto/mock.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/hashicorp/terraform/internal/tfplugin5 (interfaces: ProviderClient,ProvisionerClient,Provisioner_ProvisionResourceClient,Provisioner_ProvisionResourceServer) +// Source: github.com/hashicorp/terraform/tfplugin5 (interfaces: ProviderClient,ProvisionerClient,Provisioner_ProvisionResourceClient,Provisioner_ProvisionResourceServer) // Package mock_tfplugin5 is a generated GoMock package. package mock_tfplugin5 @@ -9,7 +9,7 @@ import ( reflect "reflect" gomock "github.com/golang/mock/gomock" - tfplugin5 "github.com/hashicorp/terraform/internal/tfplugin5" + tfplugin5 "github.com/hashicorp/terraform/tfplugin5" grpc "google.golang.org/grpc" metadata "google.golang.org/grpc/metadata" ) diff --git a/internal/plugin/plugin.go b/plugin/plugin.go similarity index 89% rename from internal/plugin/plugin.go rename to plugin/plugin.go index 27df5ba0c4b7..3f962f1131a4 100644 --- a/internal/plugin/plugin.go +++ b/plugin/plugin.go @@ -2,7 +2,7 @@ package plugin import ( "github.com/hashicorp/go-plugin" - "github.com/hashicorp/terraform/internal/plugin6" + "github.com/hashicorp/terraform/plugin6" ) // VersionedPlugins includes both protocol 5 and 6 because this is the function diff --git a/internal/plugin/serve.go b/plugin/serve.go similarity index 97% rename from internal/plugin/serve.go rename to plugin/serve.go index 27d3c9e6d46e..5b76ec29fe12 100644 --- a/internal/plugin/serve.go +++ b/plugin/serve.go @@ -2,7 +2,7 @@ package plugin import ( "github.com/hashicorp/go-plugin" - proto "github.com/hashicorp/terraform/internal/tfplugin5" + proto "github.com/hashicorp/terraform/tfplugin5" ) const ( diff --git a/internal/plugin/ui_input.go b/plugin/ui_input.go similarity index 95% rename from internal/plugin/ui_input.go rename to plugin/ui_input.go index 9a6f00a8c2fc..3469e6a96b4f 100644 --- a/internal/plugin/ui_input.go +++ b/plugin/ui_input.go @@ -5,7 +5,7 @@ import ( "net/rpc" "github.com/hashicorp/go-plugin" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/terraform" ) // UIInput is an implementation of terraform.UIInput that communicates diff --git a/internal/plugin/ui_input_test.go b/plugin/ui_input_test.go similarity index 94% rename from internal/plugin/ui_input_test.go rename to plugin/ui_input_test.go index 59cb0629a61a..c6d7036d17ec 100644 --- a/internal/plugin/ui_input_test.go +++ b/plugin/ui_input_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/hashicorp/go-plugin" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/terraform" ) func TestUIInput_impl(t *testing.T) { diff --git a/internal/plugin/ui_output.go b/plugin/ui_output.go similarity index 90% rename from internal/plugin/ui_output.go rename to plugin/ui_output.go index 130bbe30e264..c222b00cde61 100644 --- a/internal/plugin/ui_output.go +++ b/plugin/ui_output.go @@ -3,7 +3,7 @@ package plugin import ( "net/rpc" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/terraform" ) // UIOutput is an implementatin of terraform.UIOutput that communicates diff --git a/internal/plugin/ui_output_test.go b/plugin/ui_output_test.go similarity index 92% rename from internal/plugin/ui_output_test.go rename to plugin/ui_output_test.go index 5d9b8910d5e3..50eadaa02248 100644 --- a/internal/plugin/ui_output_test.go +++ b/plugin/ui_output_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/hashicorp/go-plugin" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/terraform" ) func TestUIOutput_impl(t *testing.T) { diff --git a/internal/plugin6/convert/diagnostics.go b/plugin6/convert/diagnostics.go similarity index 97% rename from internal/plugin6/convert/diagnostics.go rename to plugin6/convert/diagnostics.go index 54058533e739..1d67bd905888 100644 --- a/internal/plugin6/convert/diagnostics.go +++ b/plugin6/convert/diagnostics.go @@ -1,8 +1,8 @@ package convert import ( - "github.com/hashicorp/terraform/internal/tfdiags" - proto "github.com/hashicorp/terraform/internal/tfplugin6" + "github.com/hashicorp/terraform/tfdiags" + proto "github.com/hashicorp/terraform/tfplugin6" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/plugin6/convert/diagnostics_test.go b/plugin6/convert/diagnostics_test.go similarity index 98% rename from internal/plugin6/convert/diagnostics_test.go rename to plugin6/convert/diagnostics_test.go index 10088a05f5df..afd114f5aedf 100644 --- a/internal/plugin6/convert/diagnostics_test.go +++ b/plugin6/convert/diagnostics_test.go @@ -6,8 +6,8 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - "github.com/hashicorp/terraform/internal/tfdiags" - proto "github.com/hashicorp/terraform/internal/tfplugin6" + "github.com/hashicorp/terraform/tfdiags" + proto "github.com/hashicorp/terraform/tfplugin6" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/plugin6/convert/schema.go b/plugin6/convert/schema.go similarity index 97% rename from internal/plugin6/convert/schema.go rename to plugin6/convert/schema.go index f3c59548cbdd..1eaca37befc4 100644 --- a/internal/plugin6/convert/schema.go +++ b/plugin6/convert/schema.go @@ -5,9 +5,9 @@ import ( "reflect" "sort" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/providers" - proto "github.com/hashicorp/terraform/internal/tfplugin6" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/providers" + proto "github.com/hashicorp/terraform/tfplugin6" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/plugin6/convert/schema_test.go b/plugin6/convert/schema_test.go similarity index 99% rename from internal/plugin6/convert/schema_test.go rename to plugin6/convert/schema_test.go index 9befe4c5afb0..f132995797ba 100644 --- a/internal/plugin6/convert/schema_test.go +++ b/plugin6/convert/schema_test.go @@ -5,8 +5,8 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - "github.com/hashicorp/terraform/internal/configs/configschema" - proto "github.com/hashicorp/terraform/internal/tfplugin6" + "github.com/hashicorp/terraform/configs/configschema" + proto "github.com/hashicorp/terraform/tfplugin6" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/plugin6/doc.go b/plugin6/doc.go similarity index 100% rename from internal/plugin6/doc.go rename to plugin6/doc.go diff --git a/internal/plugin6/grpc_error.go b/plugin6/grpc_error.go similarity index 97% rename from internal/plugin6/grpc_error.go rename to plugin6/grpc_error.go index 717c1642bb71..4781d8216d04 100644 --- a/internal/plugin6/grpc_error.go +++ b/plugin6/grpc_error.go @@ -5,7 +5,7 @@ import ( "path" "runtime" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) diff --git a/internal/plugin6/grpc_provider.go b/plugin6/grpc_provider.go similarity index 98% rename from internal/plugin6/grpc_provider.go rename to plugin6/grpc_provider.go index c6530e075468..bc5257e90e0c 100644 --- a/internal/plugin6/grpc_provider.go +++ b/plugin6/grpc_provider.go @@ -9,10 +9,10 @@ import ( "github.com/zclconf/go-cty/cty" plugin "github.com/hashicorp/go-plugin" - "github.com/hashicorp/terraform/internal/logging" - "github.com/hashicorp/terraform/internal/plugin6/convert" - "github.com/hashicorp/terraform/internal/providers" - proto6 "github.com/hashicorp/terraform/internal/tfplugin6" + "github.com/hashicorp/terraform/logging" + "github.com/hashicorp/terraform/plugin6/convert" + "github.com/hashicorp/terraform/providers" + proto6 "github.com/hashicorp/terraform/tfplugin6" ctyjson "github.com/zclconf/go-cty/cty/json" "github.com/zclconf/go-cty/cty/msgpack" "google.golang.org/grpc" diff --git a/internal/plugin6/grpc_provider_test.go b/plugin6/grpc_provider_test.go similarity index 98% rename from internal/plugin6/grpc_provider_test.go rename to plugin6/grpc_provider_test.go index 300a09b4ade4..e0275f62e150 100644 --- a/internal/plugin6/grpc_provider_test.go +++ b/plugin6/grpc_provider_test.go @@ -8,13 +8,13 @@ import ( "github.com/golang/mock/gomock" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - "github.com/hashicorp/terraform/internal/configs/hcl2shim" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/configs/hcl2shim" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/tfdiags" "github.com/zclconf/go-cty/cty" - mockproto "github.com/hashicorp/terraform/internal/plugin6/mock_proto" - proto "github.com/hashicorp/terraform/internal/tfplugin6" + mockproto "github.com/hashicorp/terraform/plugin6/mock_proto" + proto "github.com/hashicorp/terraform/tfplugin6" ) var _ providers.Interface = (*GRPCProvider)(nil) diff --git a/internal/plugin6/mock_proto/generate.go b/plugin6/mock_proto/generate.go similarity index 54% rename from internal/plugin6/mock_proto/generate.go rename to plugin6/mock_proto/generate.go index cde637e4b2df..27c2f3c1dd0b 100644 --- a/internal/plugin6/mock_proto/generate.go +++ b/plugin6/mock_proto/generate.go @@ -1,3 +1,3 @@ -//go:generate go run github.com/golang/mock/mockgen -destination mock.go github.com/hashicorp/terraform/internal/tfplugin6 ProviderClient +//go:generate go run github.com/golang/mock/mockgen -destination mock.go github.com/hashicorp/terraform/tfplugin6 ProviderClient package mock_tfplugin6 diff --git a/internal/plugin6/mock_proto/mock.go b/plugin6/mock_proto/mock.go similarity index 98% rename from internal/plugin6/mock_proto/mock.go rename to plugin6/mock_proto/mock.go index 448008ef7528..b6b6e50739c0 100644 --- a/internal/plugin6/mock_proto/mock.go +++ b/plugin6/mock_proto/mock.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/hashicorp/terraform/internal/tfplugin6 (interfaces: ProviderClient) +// Source: github.com/hashicorp/terraform/tfplugin6 (interfaces: ProviderClient) // Package mock_tfplugin6 is a generated GoMock package. package mock_tfplugin6 @@ -9,7 +9,7 @@ import ( reflect "reflect" gomock "github.com/golang/mock/gomock" - tfplugin6 "github.com/hashicorp/terraform/internal/tfplugin6" + tfplugin6 "github.com/hashicorp/terraform/tfplugin6" grpc "google.golang.org/grpc" ) diff --git a/internal/plugin6/serve.go b/plugin6/serve.go similarity index 97% rename from internal/plugin6/serve.go rename to plugin6/serve.go index 8c5203fcd5e6..881c52237bb0 100644 --- a/internal/plugin6/serve.go +++ b/plugin6/serve.go @@ -2,7 +2,7 @@ package plugin6 import ( "github.com/hashicorp/go-plugin" - proto "github.com/hashicorp/terraform/internal/tfplugin6" + proto "github.com/hashicorp/terraform/tfplugin6" ) const ( diff --git a/plugins.go b/plugins.go index be576e81ac51..47ae2e4f61d9 100644 --- a/plugins.go +++ b/plugins.go @@ -6,7 +6,7 @@ import ( "path/filepath" "runtime" - "github.com/hashicorp/terraform/internal/command/cliconfig" + "github.com/hashicorp/terraform/command/cliconfig" ) // globalPluginDirs returns directories that should be searched for diff --git a/provider-simple-v6/main/main.go b/provider-simple-v6/main/main.go new file mode 100644 index 000000000000..107846b7064e --- /dev/null +++ b/provider-simple-v6/main/main.go @@ -0,0 +1,16 @@ +package main + +import ( + "github.com/hashicorp/terraform/grpcwrap" + plugin "github.com/hashicorp/terraform/plugin6" + simple "github.com/hashicorp/terraform/provider-simple-v6" + "github.com/hashicorp/terraform/tfplugin6" +) + +func main() { + plugin.Serve(&plugin.ServeOpts{ + GRPCProviderFunc: func() tfplugin6.ProviderServer { + return grpcwrap.Provider6(simple.Provider()) + }, + }) +} diff --git a/internal/provider-simple-v6/provider.go b/provider-simple-v6/provider.go similarity index 97% rename from internal/provider-simple-v6/provider.go rename to provider-simple-v6/provider.go index 1fb2ce127bf2..f6b1db61c645 100644 --- a/internal/provider-simple-v6/provider.go +++ b/provider-simple-v6/provider.go @@ -6,8 +6,8 @@ import ( "fmt" "time" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/providers" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/providers" "github.com/zclconf/go-cty/cty" ctyjson "github.com/zclconf/go-cty/cty/json" ) diff --git a/provider-simple/main/main.go b/provider-simple/main/main.go new file mode 100644 index 000000000000..d4c40b04af33 --- /dev/null +++ b/provider-simple/main/main.go @@ -0,0 +1,16 @@ +package main + +import ( + "github.com/hashicorp/terraform/grpcwrap" + "github.com/hashicorp/terraform/plugin" + simple "github.com/hashicorp/terraform/provider-simple" + "github.com/hashicorp/terraform/tfplugin5" +) + +func main() { + plugin.Serve(&plugin.ServeOpts{ + GRPCProviderFunc: func() tfplugin5.ProviderServer { + return grpcwrap.Provider(simple.Provider()) + }, + }) +} diff --git a/internal/provider-simple/provider.go b/provider-simple/provider.go similarity index 96% rename from internal/provider-simple/provider.go rename to provider-simple/provider.go index 8e32dcc10ef7..83b9d8cb3cd0 100644 --- a/internal/provider-simple/provider.go +++ b/provider-simple/provider.go @@ -5,8 +5,8 @@ import ( "errors" "time" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/providers" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/providers" "github.com/zclconf/go-cty/cty" ctyjson "github.com/zclconf/go-cty/cty/json" ) diff --git a/internal/provider-terraform/main/main.go b/provider-terraform/main/main.go similarity index 54% rename from internal/provider-terraform/main/main.go rename to provider-terraform/main/main.go index a50fef2d9b9b..7afea2f56626 100644 --- a/internal/provider-terraform/main/main.go +++ b/provider-terraform/main/main.go @@ -1,10 +1,10 @@ package main import ( - "github.com/hashicorp/terraform/internal/builtin/providers/terraform" - "github.com/hashicorp/terraform/internal/grpcwrap" - "github.com/hashicorp/terraform/internal/plugin" - "github.com/hashicorp/terraform/internal/tfplugin5" + "github.com/hashicorp/terraform/builtin/providers/terraform" + "github.com/hashicorp/terraform/grpcwrap" + "github.com/hashicorp/terraform/plugin" + "github.com/hashicorp/terraform/tfplugin5" ) func main() { diff --git a/provider_source.go b/provider_source.go index f27ca54b2a79..200d9f619739 100644 --- a/provider_source.go +++ b/provider_source.go @@ -10,10 +10,10 @@ import ( "github.com/apparentlymart/go-userdirs/userdirs" "github.com/hashicorp/terraform-svchost/disco" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/command/cliconfig" - "github.com/hashicorp/terraform/internal/getproviders" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/command/cliconfig" + "github.com/hashicorp/terraform/getproviders" + "github.com/hashicorp/terraform/tfdiags" ) // providerSource constructs a provider source based on a combination of the diff --git a/internal/providercache/cached_provider.go b/providercache/cached_provider.go similarity index 98% rename from internal/providercache/cached_provider.go rename to providercache/cached_provider.go index 0adbef21ba56..e74abe46b1aa 100644 --- a/internal/providercache/cached_provider.go +++ b/providercache/cached_provider.go @@ -6,8 +6,8 @@ import ( "path/filepath" "strings" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/getproviders" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/getproviders" ) // CachedProvider represents a provider package in a cache directory. diff --git a/internal/providercache/cached_provider_test.go b/providercache/cached_provider_test.go similarity index 97% rename from internal/providercache/cached_provider_test.go rename to providercache/cached_provider_test.go index 5e6f29fb70a6..d53f3cbecf15 100644 --- a/internal/providercache/cached_provider_test.go +++ b/providercache/cached_provider_test.go @@ -3,8 +3,8 @@ package providercache import ( "testing" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/getproviders" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/getproviders" ) func TestCachedProviderHash(t *testing.T) { diff --git a/internal/providercache/dir.go b/providercache/dir.go similarity index 98% rename from internal/providercache/dir.go rename to providercache/dir.go index f58184aa2156..2f3b8f8084a3 100644 --- a/internal/providercache/dir.go +++ b/providercache/dir.go @@ -5,8 +5,8 @@ import ( "path/filepath" "sort" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/getproviders" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/getproviders" ) // Dir represents a single local filesystem directory containing cached diff --git a/internal/providercache/dir_modify.go b/providercache/dir_modify.go similarity index 98% rename from internal/providercache/dir_modify.go rename to providercache/dir_modify.go index 5ac79ba4f74f..29ae18e37cc8 100644 --- a/internal/providercache/dir_modify.go +++ b/providercache/dir_modify.go @@ -5,7 +5,7 @@ import ( "fmt" "log" - "github.com/hashicorp/terraform/internal/getproviders" + "github.com/hashicorp/terraform/getproviders" ) // InstallPackage takes a metadata object describing a package available for diff --git a/internal/providercache/dir_modify_test.go b/providercache/dir_modify_test.go similarity index 97% rename from internal/providercache/dir_modify_test.go rename to providercache/dir_modify_test.go index 6e7821b575c1..681895b76c98 100644 --- a/internal/providercache/dir_modify_test.go +++ b/providercache/dir_modify_test.go @@ -8,8 +8,8 @@ import ( "github.com/apparentlymart/go-versions/versions" "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/getproviders" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/getproviders" ) func TestInstallPackage(t *testing.T) { diff --git a/internal/providercache/dir_test.go b/providercache/dir_test.go similarity index 98% rename from internal/providercache/dir_test.go rename to providercache/dir_test.go index 799a149e3290..f757c113f494 100644 --- a/internal/providercache/dir_test.go +++ b/providercache/dir_test.go @@ -6,8 +6,8 @@ import ( "github.com/apparentlymart/go-versions/versions" "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/getproviders" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/getproviders" ) func TestDirReading(t *testing.T) { diff --git a/internal/providercache/doc.go b/providercache/doc.go similarity index 100% rename from internal/providercache/doc.go rename to providercache/doc.go diff --git a/internal/providercache/installer.go b/providercache/installer.go similarity index 99% rename from internal/providercache/installer.go rename to providercache/installer.go index 62e57cc2b233..68f041ac2546 100644 --- a/internal/providercache/installer.go +++ b/providercache/installer.go @@ -9,10 +9,10 @@ import ( "github.com/apparentlymart/go-versions/versions" - "github.com/hashicorp/terraform/internal/addrs" - copydir "github.com/hashicorp/terraform/internal/copy" - "github.com/hashicorp/terraform/internal/depsfile" - "github.com/hashicorp/terraform/internal/getproviders" + "github.com/hashicorp/terraform/addrs" + copydir "github.com/hashicorp/terraform/copy" + "github.com/hashicorp/terraform/depsfile" + "github.com/hashicorp/terraform/getproviders" ) // Installer is the main type in this package, representing a provider installer diff --git a/internal/providercache/installer_events.go b/providercache/installer_events.go similarity index 98% rename from internal/providercache/installer_events.go rename to providercache/installer_events.go index 8fc579af2666..26f7bd541346 100644 --- a/internal/providercache/installer_events.go +++ b/providercache/installer_events.go @@ -3,8 +3,8 @@ package providercache import ( "context" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/getproviders" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/getproviders" ) // InstallerEvents is a collection of function references that can be diff --git a/internal/providercache/installer_events_test.go b/providercache/installer_events_test.go similarity index 98% rename from internal/providercache/installer_events_test.go rename to providercache/installer_events_test.go index cde5b7f0abf5..21a13ce1590c 100644 --- a/internal/providercache/installer_events_test.go +++ b/providercache/installer_events_test.go @@ -1,8 +1,8 @@ package providercache import ( - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/getproviders" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/getproviders" ) type testInstallerEventLogItem struct { diff --git a/internal/providercache/installer_test.go b/providercache/installer_test.go similarity index 99% rename from internal/providercache/installer_test.go rename to providercache/installer_test.go index c0cfd7b03070..abcbb4f318b2 100644 --- a/internal/providercache/installer_test.go +++ b/providercache/installer_test.go @@ -18,9 +18,9 @@ import ( svchost "github.com/hashicorp/terraform-svchost" "github.com/hashicorp/terraform-svchost/disco" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/depsfile" - "github.com/hashicorp/terraform/internal/getproviders" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/depsfile" + "github.com/hashicorp/terraform/getproviders" ) func TestEnsureProviderVersions(t *testing.T) { diff --git a/internal/providercache/package_install.go b/providercache/package_install.go similarity index 98% rename from internal/providercache/package_install.go rename to providercache/package_install.go index 89ef862cec1f..5930fe311279 100644 --- a/internal/providercache/package_install.go +++ b/providercache/package_install.go @@ -10,9 +10,9 @@ import ( getter "github.com/hashicorp/go-getter" - "github.com/hashicorp/terraform/internal/copy" - "github.com/hashicorp/terraform/internal/getproviders" - "github.com/hashicorp/terraform/internal/httpclient" + "github.com/hashicorp/terraform/copy" + "github.com/hashicorp/terraform/getproviders" + "github.com/hashicorp/terraform/httpclient" ) // We borrow the "unpack a zip file into a target directory" logic from diff --git a/internal/providercache/testdata/beep-provider-other-platform/terraform-provider-beep b/providercache/testdata/beep-provider-other-platform/terraform-provider-beep similarity index 100% rename from internal/providercache/testdata/beep-provider-other-platform/terraform-provider-beep rename to providercache/testdata/beep-provider-other-platform/terraform-provider-beep diff --git a/internal/providercache/testdata/beep-provider/terraform-provider-beep b/providercache/testdata/beep-provider/terraform-provider-beep similarity index 100% rename from internal/providercache/testdata/beep-provider/terraform-provider-beep rename to providercache/testdata/beep-provider/terraform-provider-beep diff --git a/internal/providercache/testdata/cachedir/registry.terraform.io/-/legacy/1.0.0/linux_amd64/terraform-provider-legacy b/providercache/testdata/cachedir/registry.terraform.io/-/legacy/1.0.0/linux_amd64/terraform-provider-legacy similarity index 100% rename from internal/providercache/testdata/cachedir/registry.terraform.io/-/legacy/1.0.0/linux_amd64/terraform-provider-legacy rename to providercache/testdata/cachedir/registry.terraform.io/-/legacy/1.0.0/linux_amd64/terraform-provider-legacy diff --git a/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/darwin_amd64/terraform-provider-null b/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/darwin_amd64/terraform-provider-null similarity index 100% rename from internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/darwin_amd64/terraform-provider-null rename to providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/darwin_amd64/terraform-provider-null diff --git a/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/linux_amd64/terraform-provider-null b/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/linux_amd64/terraform-provider-null similarity index 100% rename from internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/linux_amd64/terraform-provider-null rename to providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/linux_amd64/terraform-provider-null diff --git a/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/invalid b/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/invalid similarity index 100% rename from internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/invalid rename to providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/invalid diff --git a/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip b/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip similarity index 100% rename from internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip rename to providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip diff --git a/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/terraform-provider-null_invalid.zip b/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/terraform-provider-null_invalid.zip similarity index 100% rename from internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/terraform-provider-null_invalid.zip rename to providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/terraform-provider-null_invalid.zip diff --git a/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/terraform-provider-null_invalid_invalid_invalid.zip b/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/terraform-provider-null_invalid_invalid_invalid.zip similarity index 100% rename from internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/terraform-provider-null_invalid_invalid_invalid.zip rename to providercache/testdata/cachedir/registry.terraform.io/hashicorp/null/terraform-provider-null_invalid_invalid_invalid.zip diff --git a/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/random-beta/1.2.0/linux_amd64/terraform-provider-random-beta b/providercache/testdata/cachedir/registry.terraform.io/hashicorp/random-beta/1.2.0/linux_amd64/terraform-provider-random-beta similarity index 100% rename from internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/random-beta/1.2.0/linux_amd64/terraform-provider-random-beta rename to providercache/testdata/cachedir/registry.terraform.io/hashicorp/random-beta/1.2.0/linux_amd64/terraform-provider-random-beta diff --git a/internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/random/1.2.0/linux_amd64/terraform-provider-random b/providercache/testdata/cachedir/registry.terraform.io/hashicorp/random/1.2.0/linux_amd64/terraform-provider-random similarity index 100% rename from internal/providercache/testdata/cachedir/registry.terraform.io/hashicorp/random/1.2.0/linux_amd64/terraform-provider-random rename to providercache/testdata/cachedir/registry.terraform.io/hashicorp/random/1.2.0/linux_amd64/terraform-provider-random diff --git a/internal/providercache/testdata/cachedir/registry.terraform.io/missing/executable/2.0.0/linux_amd64/executable b/providercache/testdata/cachedir/registry.terraform.io/missing/executable/2.0.0/linux_amd64/executable similarity index 100% rename from internal/providercache/testdata/cachedir/registry.terraform.io/missing/executable/2.0.0/linux_amd64/executable rename to providercache/testdata/cachedir/registry.terraform.io/missing/executable/2.0.0/linux_amd64/executable diff --git a/internal/providercache/testdata/cachedir/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64/extra-data.txt b/providercache/testdata/cachedir/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64/extra-data.txt similarity index 100% rename from internal/providercache/testdata/cachedir/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64/extra-data.txt rename to providercache/testdata/cachedir/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64/extra-data.txt diff --git a/internal/providercache/testdata/cachedir/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64/terraform-provider-happycloud b/providercache/testdata/cachedir/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64/terraform-provider-happycloud similarity index 100% rename from internal/providercache/testdata/cachedir/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64/terraform-provider-happycloud rename to providercache/testdata/cachedir/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64/terraform-provider-happycloud diff --git a/internal/providercache/testdata/terraform-provider-null_2.1.0_linux_amd64.zip b/providercache/testdata/terraform-provider-null_2.1.0_linux_amd64.zip similarity index 100% rename from internal/providercache/testdata/terraform-provider-null_2.1.0_linux_amd64.zip rename to providercache/testdata/terraform-provider-null_2.1.0_linux_amd64.zip diff --git a/internal/providers/addressed_types.go b/providers/addressed_types.go similarity index 93% rename from internal/providers/addressed_types.go rename to providers/addressed_types.go index 8efa82ca3e72..85ff4c962d35 100644 --- a/internal/providers/addressed_types.go +++ b/providers/addressed_types.go @@ -3,7 +3,7 @@ package providers import ( "sort" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) // AddressedTypesAbs is a helper that extracts all of the distinct provider diff --git a/internal/providers/addressed_types_test.go b/providers/addressed_types_test.go similarity index 95% rename from internal/providers/addressed_types_test.go rename to providers/addressed_types_test.go index 3bb47667050e..0d45f44b33fb 100644 --- a/internal/providers/addressed_types_test.go +++ b/providers/addressed_types_test.go @@ -5,7 +5,7 @@ import ( "github.com/go-test/deep" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) func TestAddressedTypesAbs(t *testing.T) { diff --git a/internal/providers/doc.go b/providers/doc.go similarity index 100% rename from internal/providers/doc.go rename to providers/doc.go diff --git a/internal/providers/factory.go b/providers/factory.go similarity index 100% rename from internal/providers/factory.go rename to providers/factory.go diff --git a/internal/providers/provider.go b/providers/provider.go similarity index 99% rename from internal/providers/provider.go rename to providers/provider.go index 5d98d9bf3917..f983f98dfa9d 100644 --- a/internal/providers/provider.go +++ b/providers/provider.go @@ -3,8 +3,8 @@ package providers import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/tfdiags" ) // Interface represents the set of methods required for a complete resource diff --git a/internal/providers/schemas.go b/providers/schemas.go similarity index 95% rename from internal/providers/schemas.go rename to providers/schemas.go index 213ff4f0e588..35b69b60fc5c 100644 --- a/internal/providers/schemas.go +++ b/providers/schemas.go @@ -1,8 +1,8 @@ package providers import ( - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs/configschema" ) // Schemas is an overall container for all of the schemas for all configurable diff --git a/internal/provisioner-local-exec/main/main.go b/provisioner-local-exec/main/main.go similarity index 52% rename from internal/provisioner-local-exec/main/main.go rename to provisioner-local-exec/main/main.go index 78f14b37afc4..1c5050e079b5 100644 --- a/internal/provisioner-local-exec/main/main.go +++ b/provisioner-local-exec/main/main.go @@ -1,10 +1,10 @@ package main import ( - localexec "github.com/hashicorp/terraform/internal/builtin/provisioners/local-exec" - "github.com/hashicorp/terraform/internal/grpcwrap" - "github.com/hashicorp/terraform/internal/plugin" - "github.com/hashicorp/terraform/internal/tfplugin5" + localexec "github.com/hashicorp/terraform/builtin/provisioners/local-exec" + "github.com/hashicorp/terraform/grpcwrap" + "github.com/hashicorp/terraform/plugin" + "github.com/hashicorp/terraform/tfplugin5" ) func main() { diff --git a/internal/provisioners/doc.go b/provisioners/doc.go similarity index 100% rename from internal/provisioners/doc.go rename to provisioners/doc.go diff --git a/internal/provisioners/factory.go b/provisioners/factory.go similarity index 100% rename from internal/provisioners/factory.go rename to provisioners/factory.go diff --git a/internal/provisioners/provisioner.go b/provisioners/provisioner.go similarity index 95% rename from internal/provisioners/provisioner.go rename to provisioners/provisioner.go index 190740a7fe49..e53c88488e80 100644 --- a/internal/provisioners/provisioner.go +++ b/provisioners/provisioner.go @@ -1,8 +1,8 @@ package provisioners import ( - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/tfdiags" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/refactoring/move_execute.go b/refactoring/move_execute.go similarity index 98% rename from internal/refactoring/move_execute.go rename to refactoring/move_execute.go index 9a6d577cfb4f..90cf843712ed 100644 --- a/internal/refactoring/move_execute.go +++ b/refactoring/move_execute.go @@ -4,10 +4,10 @@ import ( "fmt" "log" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/dag" - "github.com/hashicorp/terraform/internal/logging" - "github.com/hashicorp/terraform/internal/states" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/dag" + "github.com/hashicorp/terraform/logging" + "github.com/hashicorp/terraform/states" ) // ApplyMoves modifies in-place the given state object so that any existing diff --git a/internal/refactoring/move_execute_test.go b/refactoring/move_execute_test.go similarity index 99% rename from internal/refactoring/move_execute_test.go rename to refactoring/move_execute_test.go index edc8afb9fda9..ba2b949bfd43 100644 --- a/internal/refactoring/move_execute_test.go +++ b/refactoring/move_execute_test.go @@ -11,8 +11,8 @@ import ( "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/states" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/states" ) func TestApplyMoves(t *testing.T) { diff --git a/internal/refactoring/move_statement.go b/refactoring/move_statement.go similarity index 97% rename from internal/refactoring/move_statement.go rename to refactoring/move_statement.go index 08fffeb6f47f..1c1dd75e1381 100644 --- a/internal/refactoring/move_statement.go +++ b/refactoring/move_statement.go @@ -3,10 +3,10 @@ package refactoring import ( "fmt" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/tfdiags" ) type MoveStatement struct { diff --git a/internal/refactoring/move_statement_test.go b/refactoring/move_statement_test.go similarity index 97% rename from internal/refactoring/move_statement_test.go rename to refactoring/move_statement_test.go index a6f0f9f6eee2..084716e4341f 100644 --- a/internal/refactoring/move_statement_test.go +++ b/refactoring/move_statement_test.go @@ -6,9 +6,9 @@ import ( "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/tfdiags" ) func TestImpliedMoveStatements(t *testing.T) { diff --git a/internal/refactoring/move_validate.go b/refactoring/move_validate.go similarity index 97% rename from internal/refactoring/move_validate.go rename to refactoring/move_validate.go index 585f62368732..51276efac719 100644 --- a/internal/refactoring/move_validate.go +++ b/refactoring/move_validate.go @@ -7,11 +7,11 @@ import ( "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/dag" - "github.com/hashicorp/terraform/internal/instances" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/dag" + "github.com/hashicorp/terraform/instances" + "github.com/hashicorp/terraform/tfdiags" ) // ValidateMoves tests whether all of the given move statements comply with diff --git a/internal/refactoring/move_validate_test.go b/refactoring/move_validate_test.go similarity index 98% rename from internal/refactoring/move_validate_test.go rename to refactoring/move_validate_test.go index 56d767af51cd..5abb1fa0bb14 100644 --- a/internal/refactoring/move_validate_test.go +++ b/refactoring/move_validate_test.go @@ -9,13 +9,13 @@ import ( "github.com/hashicorp/hcl/v2/hclsyntax" "github.com/zclconf/go-cty/cty/gocty" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/configs/configload" - "github.com/hashicorp/terraform/internal/initwd" - "github.com/hashicorp/terraform/internal/instances" - "github.com/hashicorp/terraform/internal/registry" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/initwd" + "github.com/hashicorp/terraform/instances" + "github.com/hashicorp/terraform/registry" + "github.com/hashicorp/terraform/tfdiags" ) func TestValidateMoves(t *testing.T) { diff --git a/internal/refactoring/testdata/move-statement-implied/child/move-statement-implied.tf b/refactoring/testdata/move-statement-implied/child/move-statement-implied.tf similarity index 100% rename from internal/refactoring/testdata/move-statement-implied/child/move-statement-implied.tf rename to refactoring/testdata/move-statement-implied/child/move-statement-implied.tf diff --git a/internal/refactoring/testdata/move-statement-implied/move-statement-implied.tf b/refactoring/testdata/move-statement-implied/move-statement-implied.tf similarity index 100% rename from internal/refactoring/testdata/move-statement-implied/move-statement-implied.tf rename to refactoring/testdata/move-statement-implied/move-statement-implied.tf diff --git a/internal/refactoring/testdata/move-validate-zoo/child/move-validate-child.tf b/refactoring/testdata/move-validate-zoo/child/move-validate-child.tf similarity index 100% rename from internal/refactoring/testdata/move-validate-zoo/child/move-validate-child.tf rename to refactoring/testdata/move-validate-zoo/child/move-validate-child.tf diff --git a/internal/refactoring/testdata/move-validate-zoo/move-validate-root.tf b/refactoring/testdata/move-validate-zoo/move-validate-root.tf similarity index 100% rename from internal/refactoring/testdata/move-validate-zoo/move-validate-root.tf rename to refactoring/testdata/move-validate-zoo/move-validate-root.tf diff --git a/internal/registry/client.go b/registry/client.go similarity index 97% rename from internal/registry/client.go rename to registry/client.go index 0204674bbf05..987e80bdae2e 100644 --- a/internal/registry/client.go +++ b/registry/client.go @@ -17,10 +17,10 @@ import ( "github.com/hashicorp/go-retryablehttp" svchost "github.com/hashicorp/terraform-svchost" "github.com/hashicorp/terraform-svchost/disco" - "github.com/hashicorp/terraform/internal/httpclient" - "github.com/hashicorp/terraform/internal/logging" - "github.com/hashicorp/terraform/internal/registry/regsrc" - "github.com/hashicorp/terraform/internal/registry/response" + "github.com/hashicorp/terraform/httpclient" + "github.com/hashicorp/terraform/logging" + "github.com/hashicorp/terraform/registry/regsrc" + "github.com/hashicorp/terraform/registry/response" "github.com/hashicorp/terraform/version" ) diff --git a/internal/registry/client_test.go b/registry/client_test.go similarity index 98% rename from internal/registry/client_test.go rename to registry/client_test.go index da3055110a0c..4195aa6e267f 100644 --- a/internal/registry/client_test.go +++ b/registry/client_test.go @@ -10,9 +10,9 @@ import ( version "github.com/hashicorp/go-version" "github.com/hashicorp/terraform-svchost/disco" - "github.com/hashicorp/terraform/internal/httpclient" - "github.com/hashicorp/terraform/internal/registry/regsrc" - "github.com/hashicorp/terraform/internal/registry/test" + "github.com/hashicorp/terraform/httpclient" + "github.com/hashicorp/terraform/registry/regsrc" + "github.com/hashicorp/terraform/registry/test" tfversion "github.com/hashicorp/terraform/version" ) diff --git a/internal/registry/errors.go b/registry/errors.go similarity index 95% rename from internal/registry/errors.go rename to registry/errors.go index a35eb717ed25..5ae022fd2e71 100644 --- a/internal/registry/errors.go +++ b/registry/errors.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/hashicorp/terraform-svchost/disco" - "github.com/hashicorp/terraform/internal/registry/regsrc" + "github.com/hashicorp/terraform/registry/regsrc" ) type errModuleNotFound struct { diff --git a/internal/registry/regsrc/friendly_host.go b/registry/regsrc/friendly_host.go similarity index 100% rename from internal/registry/regsrc/friendly_host.go rename to registry/regsrc/friendly_host.go diff --git a/internal/registry/regsrc/friendly_host_test.go b/registry/regsrc/friendly_host_test.go similarity index 100% rename from internal/registry/regsrc/friendly_host_test.go rename to registry/regsrc/friendly_host_test.go diff --git a/internal/registry/regsrc/module.go b/registry/regsrc/module.go similarity index 99% rename from internal/registry/regsrc/module.go rename to registry/regsrc/module.go index 3ffa002bba07..7bd1f8e41a25 100644 --- a/internal/registry/regsrc/module.go +++ b/registry/regsrc/module.go @@ -7,7 +7,7 @@ import ( "strings" svchost "github.com/hashicorp/terraform-svchost" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) var ( diff --git a/internal/registry/regsrc/module_test.go b/registry/regsrc/module_test.go similarity index 100% rename from internal/registry/regsrc/module_test.go rename to registry/regsrc/module_test.go diff --git a/internal/registry/regsrc/regsrc.go b/registry/regsrc/regsrc.go similarity index 100% rename from internal/registry/regsrc/regsrc.go rename to registry/regsrc/regsrc.go diff --git a/internal/registry/response/module.go b/registry/response/module.go similarity index 100% rename from internal/registry/response/module.go rename to registry/response/module.go diff --git a/internal/registry/response/module_list.go b/registry/response/module_list.go similarity index 100% rename from internal/registry/response/module_list.go rename to registry/response/module_list.go diff --git a/internal/registry/response/module_provider.go b/registry/response/module_provider.go similarity index 100% rename from internal/registry/response/module_provider.go rename to registry/response/module_provider.go diff --git a/internal/registry/response/module_versions.go b/registry/response/module_versions.go similarity index 100% rename from internal/registry/response/module_versions.go rename to registry/response/module_versions.go diff --git a/internal/registry/response/pagination.go b/registry/response/pagination.go similarity index 100% rename from internal/registry/response/pagination.go rename to registry/response/pagination.go diff --git a/internal/registry/response/pagination_test.go b/registry/response/pagination_test.go similarity index 100% rename from internal/registry/response/pagination_test.go rename to registry/response/pagination_test.go diff --git a/internal/registry/response/redirect.go b/registry/response/redirect.go similarity index 100% rename from internal/registry/response/redirect.go rename to registry/response/redirect.go diff --git a/internal/registry/test/mock_registry.go b/registry/test/mock_registry.go similarity index 97% rename from internal/registry/test/mock_registry.go rename to registry/test/mock_registry.go index 079df1bfea9f..00ead006e534 100644 --- a/internal/registry/test/mock_registry.go +++ b/registry/test/mock_registry.go @@ -13,9 +13,9 @@ import ( svchost "github.com/hashicorp/terraform-svchost" "github.com/hashicorp/terraform-svchost/auth" "github.com/hashicorp/terraform-svchost/disco" - "github.com/hashicorp/terraform/internal/httpclient" - "github.com/hashicorp/terraform/internal/registry/regsrc" - "github.com/hashicorp/terraform/internal/registry/response" + "github.com/hashicorp/terraform/httpclient" + "github.com/hashicorp/terraform/registry/regsrc" + "github.com/hashicorp/terraform/registry/response" tfversion "github.com/hashicorp/terraform/version" ) diff --git a/internal/repl/format.go b/repl/format.go similarity index 98% rename from internal/repl/format.go rename to repl/format.go index c65ad048b3b3..74cea8411072 100644 --- a/internal/repl/format.go +++ b/repl/format.go @@ -5,7 +5,7 @@ import ( "strconv" "strings" - "github.com/hashicorp/terraform/internal/lang/marks" + "github.com/hashicorp/terraform/lang/marks" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/repl/format_test.go b/repl/format_test.go similarity index 98% rename from internal/repl/format_test.go rename to repl/format_test.go index 31843bbe010b..5576af6651fc 100644 --- a/internal/repl/format_test.go +++ b/repl/format_test.go @@ -4,7 +4,7 @@ import ( "fmt" "testing" - "github.com/hashicorp/terraform/internal/lang/marks" + "github.com/hashicorp/terraform/lang/marks" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/repl/repl.go b/repl/repl.go similarity index 100% rename from internal/repl/repl.go rename to repl/repl.go diff --git a/internal/repl/session.go b/repl/session.go similarity index 96% rename from internal/repl/session.go rename to repl/session.go index f07363ec1a16..2d3c7cee463f 100644 --- a/internal/repl/session.go +++ b/repl/session.go @@ -9,10 +9,10 @@ import ( "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/hashicorp/terraform/internal/lang" - "github.com/hashicorp/terraform/internal/lang/marks" - "github.com/hashicorp/terraform/internal/lang/types" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/lang" + "github.com/hashicorp/terraform/lang/marks" + "github.com/hashicorp/terraform/lang/types" + "github.com/hashicorp/terraform/tfdiags" ) // Session represents the state for a single REPL session. diff --git a/internal/repl/session_test.go b/repl/session_test.go similarity index 96% rename from internal/repl/session_test.go rename to repl/session_test.go index 3e976cadc0bf..a09f05fa456a 100644 --- a/internal/repl/session_test.go +++ b/repl/session_test.go @@ -9,14 +9,14 @@ import ( "github.com/google/go-cmp/cmp" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/configschema" - "github.com/hashicorp/terraform/internal/initwd" - "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/terraform" - - _ "github.com/hashicorp/terraform/internal/logging" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/initwd" + "github.com/hashicorp/terraform/providers" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/terraform" + + _ "github.com/hashicorp/terraform/logging" ) func TestMain(m *testing.M) { diff --git a/internal/repl/testdata/config-fixture/child/empty.tf b/repl/testdata/config-fixture/child/empty.tf similarity index 100% rename from internal/repl/testdata/config-fixture/child/empty.tf rename to repl/testdata/config-fixture/child/empty.tf diff --git a/internal/repl/testdata/config-fixture/repl_test.tf b/repl/testdata/config-fixture/repl_test.tf similarity index 100% rename from internal/repl/testdata/config-fixture/repl_test.tf rename to repl/testdata/config-fixture/repl_test.tf diff --git a/internal/replacefile/doc.go b/replacefile/doc.go similarity index 100% rename from internal/replacefile/doc.go rename to replacefile/doc.go diff --git a/internal/replacefile/replacefile_unix.go b/replacefile/replacefile_unix.go similarity index 100% rename from internal/replacefile/replacefile_unix.go rename to replacefile/replacefile_unix.go diff --git a/internal/replacefile/replacefile_windows.go b/replacefile/replacefile_windows.go similarity index 100% rename from internal/replacefile/replacefile_windows.go rename to replacefile/replacefile_windows.go diff --git a/internal/replacefile/writefile.go b/replacefile/writefile.go similarity index 100% rename from internal/replacefile/writefile.go rename to replacefile/writefile.go diff --git a/internal/states/checks.go b/states/checks.go similarity index 98% rename from internal/states/checks.go rename to states/checks.go index 181871a766da..4557fa5d0dac 100644 --- a/internal/states/checks.go +++ b/states/checks.go @@ -1,8 +1,8 @@ package states import ( - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/checks" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/checks" ) // CheckResults represents a summary snapshot of the status of a set of checks diff --git a/internal/states/doc.go b/states/doc.go similarity index 100% rename from internal/states/doc.go rename to states/doc.go diff --git a/internal/states/instance_generation.go b/states/instance_generation.go similarity index 100% rename from internal/states/instance_generation.go rename to states/instance_generation.go diff --git a/internal/states/instance_object.go b/states/instance_object.go similarity index 99% rename from internal/states/instance_object.go rename to states/instance_object.go index 0e790bba1a66..a52a5ec6aa1a 100644 --- a/internal/states/instance_object.go +++ b/states/instance_object.go @@ -6,7 +6,7 @@ import ( "github.com/zclconf/go-cty/cty" ctyjson "github.com/zclconf/go-cty/cty/json" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) // ResourceInstanceObject is the local representation of a specific remote diff --git a/internal/states/instance_object_src.go b/states/instance_object_src.go similarity index 97% rename from internal/states/instance_object_src.go rename to states/instance_object_src.go index a564e0d90778..aeb612eaa8a4 100644 --- a/internal/states/instance_object_src.go +++ b/states/instance_object_src.go @@ -4,8 +4,8 @@ import ( "github.com/zclconf/go-cty/cty" ctyjson "github.com/zclconf/go-cty/cty/json" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/hcl2shim" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs/hcl2shim" ) // ResourceInstanceObjectSrc is a not-fully-decoded version of diff --git a/internal/states/instance_object_test.go b/states/instance_object_test.go similarity index 97% rename from internal/states/instance_object_test.go rename to states/instance_object_test.go index e7f4eca6a084..1c781f0a8749 100644 --- a/internal/states/instance_object_test.go +++ b/states/instance_object_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/states/module.go b/states/module.go similarity index 99% rename from internal/states/module.go rename to states/module.go index 2f6242ace522..fbef01c7a9ee 100644 --- a/internal/states/module.go +++ b/states/module.go @@ -3,7 +3,7 @@ package states import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) // Module is a container for the states of objects within a particular module. diff --git a/internal/states/objectstatus_string.go b/states/objectstatus_string.go similarity index 100% rename from internal/states/objectstatus_string.go rename to states/objectstatus_string.go diff --git a/internal/states/output_value.go b/states/output_value.go similarity index 88% rename from internal/states/output_value.go rename to states/output_value.go index 541595164805..268420cf4ad5 100644 --- a/internal/states/output_value.go +++ b/states/output_value.go @@ -1,7 +1,7 @@ package states import ( - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/states/remote/remote.go b/states/remote/remote.go similarity index 94% rename from internal/states/remote/remote.go rename to states/remote/remote.go index a87c9145a830..0dab1863ce48 100644 --- a/internal/states/remote/remote.go +++ b/states/remote/remote.go @@ -1,7 +1,7 @@ package remote import ( - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/states/statemgr" ) // Client is the interface that must be implemented for a remote state diff --git a/internal/states/remote/remote_test.go b/states/remote/remote_test.go similarity index 100% rename from internal/states/remote/remote_test.go rename to states/remote/remote_test.go diff --git a/internal/states/remote/state.go b/states/remote/state.go similarity index 97% rename from internal/states/remote/state.go rename to states/remote/state.go index d8da9d827adb..9a2addf54189 100644 --- a/internal/states/remote/state.go +++ b/states/remote/state.go @@ -8,10 +8,10 @@ import ( uuid "github.com/hashicorp/go-uuid" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/statefile" - "github.com/hashicorp/terraform/internal/states/statemgr" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/statefile" + "github.com/hashicorp/terraform/states/statemgr" + "github.com/hashicorp/terraform/terraform" ) // State implements the State interfaces in the state package to handle diff --git a/internal/states/remote/state_test.go b/states/remote/state_test.go similarity index 99% rename from internal/states/remote/state_test.go rename to states/remote/state_test.go index 71e86c65703c..00dc2621a4d9 100644 --- a/internal/states/remote/state_test.go +++ b/states/remote/state_test.go @@ -10,10 +10,10 @@ import ( "github.com/zclconf/go-cty/cty" tfaddr "github.com/hashicorp/terraform-registry-address" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/statefile" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/statefile" + "github.com/hashicorp/terraform/states/statemgr" "github.com/hashicorp/terraform/version" ) diff --git a/internal/states/remote/testing.go b/states/remote/testing.go similarity index 94% rename from internal/states/remote/testing.go rename to states/remote/testing.go index 197f87ac8c12..cbd7586b3e30 100644 --- a/internal/states/remote/testing.go +++ b/states/remote/testing.go @@ -4,8 +4,8 @@ import ( "bytes" "testing" - "github.com/hashicorp/terraform/internal/states/statefile" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/states/statefile" + "github.com/hashicorp/terraform/states/statemgr" ) // TestClient is a generic function to test any client. diff --git a/internal/states/resource.go b/states/resource.go similarity index 99% rename from internal/states/resource.go rename to states/resource.go index 1c1f65bedef4..28223671d5a8 100644 --- a/internal/states/resource.go +++ b/states/resource.go @@ -5,7 +5,7 @@ import ( "math/rand" "time" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) // Resource represents the state of a resource. diff --git a/internal/states/resource_test.go b/states/resource_test.go similarity index 100% rename from internal/states/resource_test.go rename to states/resource_test.go diff --git a/internal/states/state.go b/states/state.go similarity index 99% rename from internal/states/state.go rename to states/state.go index 9992f93caf7e..39afe1e4005d 100644 --- a/internal/states/state.go +++ b/states/state.go @@ -6,8 +6,8 @@ import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/getproviders" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/getproviders" ) // State is the top-level type of a Terraform state. diff --git a/internal/states/state_deepcopy.go b/states/state_deepcopy.go similarity index 99% rename from internal/states/state_deepcopy.go rename to states/state_deepcopy.go index b8498d53ff11..6204f3e4879b 100644 --- a/internal/states/state_deepcopy.go +++ b/states/state_deepcopy.go @@ -1,7 +1,7 @@ package states import ( - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/states/state_equal.go b/states/state_equal.go similarity index 97% rename from internal/states/state_equal.go rename to states/state_equal.go index b37aba062768..1e6c04c5d12b 100644 --- a/internal/states/state_equal.go +++ b/states/state_equal.go @@ -3,7 +3,7 @@ package states import ( "reflect" - "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/addrs" ) // Equal returns true if the receiver is functionally equivalent to other, diff --git a/internal/states/state_string.go b/states/state_string.go similarity index 98% rename from internal/states/state_string.go rename to states/state_string.go index 2e34834a5518..0f74d5965924 100644 --- a/internal/states/state_string.go +++ b/states/state_string.go @@ -10,8 +10,8 @@ import ( ctyjson "github.com/zclconf/go-cty/cty/json" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs/hcl2shim" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs/hcl2shim" ) // String returns a rather-odd string representation of the entire state. diff --git a/internal/states/state_test.go b/states/state_test.go similarity index 99% rename from internal/states/state_test.go rename to states/state_test.go index 768772aebe44..fe43d8644c24 100644 --- a/internal/states/state_test.go +++ b/states/state_test.go @@ -8,8 +8,8 @@ import ( "github.com/go-test/deep" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/lang/marks" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/lang/marks" ) func TestState(t *testing.T) { diff --git a/internal/states/statefile/diagnostics.go b/states/statefile/diagnostics.go similarity index 97% rename from internal/states/statefile/diagnostics.go rename to states/statefile/diagnostics.go index b45b05ee0b3e..a6d88ecd5844 100644 --- a/internal/states/statefile/diagnostics.go +++ b/states/statefile/diagnostics.go @@ -4,7 +4,7 @@ import ( "encoding/json" "fmt" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" ) const invalidFormat = "Invalid state file format" diff --git a/internal/states/statefile/doc.go b/states/statefile/doc.go similarity index 100% rename from internal/states/statefile/doc.go rename to states/statefile/doc.go diff --git a/internal/states/statefile/file.go b/states/statefile/file.go similarity index 97% rename from internal/states/statefile/file.go rename to states/statefile/file.go index 631807b11301..6e202401999b 100644 --- a/internal/states/statefile/file.go +++ b/states/statefile/file.go @@ -3,7 +3,7 @@ package statefile import ( version "github.com/hashicorp/go-version" - "github.com/hashicorp/terraform/internal/states" + "github.com/hashicorp/terraform/states" tfversion "github.com/hashicorp/terraform/version" ) diff --git a/internal/states/statefile/marshal_equal.go b/states/statefile/marshal_equal.go similarity index 95% rename from internal/states/statefile/marshal_equal.go rename to states/statefile/marshal_equal.go index 2b386cbb7389..4948b39b9ed0 100644 --- a/internal/states/statefile/marshal_equal.go +++ b/states/statefile/marshal_equal.go @@ -3,7 +3,7 @@ package statefile import ( "bytes" - "github.com/hashicorp/terraform/internal/states" + "github.com/hashicorp/terraform/states" ) // StatesMarshalEqual returns true if and only if the two given states have diff --git a/internal/states/statefile/read.go b/states/statefile/read.go similarity index 99% rename from internal/states/statefile/read.go rename to states/statefile/read.go index 61f8e87d6c7a..8abd3be14da2 100644 --- a/internal/states/statefile/read.go +++ b/states/statefile/read.go @@ -10,7 +10,7 @@ import ( version "github.com/hashicorp/go-version" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" tfversion "github.com/hashicorp/terraform/version" ) diff --git a/internal/states/statefile/roundtrip_test.go b/states/statefile/roundtrip_test.go similarity index 100% rename from internal/states/statefile/roundtrip_test.go rename to states/statefile/roundtrip_test.go diff --git a/internal/states/statefile/testdata/roundtrip/v1-simple.in.tfstate b/states/statefile/testdata/roundtrip/v1-simple.in.tfstate similarity index 100% rename from internal/states/statefile/testdata/roundtrip/v1-simple.in.tfstate rename to states/statefile/testdata/roundtrip/v1-simple.in.tfstate diff --git a/internal/states/statefile/testdata/roundtrip/v1-simple.out.tfstate b/states/statefile/testdata/roundtrip/v1-simple.out.tfstate similarity index 100% rename from internal/states/statefile/testdata/roundtrip/v1-simple.out.tfstate rename to states/statefile/testdata/roundtrip/v1-simple.out.tfstate diff --git a/internal/states/statefile/testdata/roundtrip/v3-bigint.in.tfstate b/states/statefile/testdata/roundtrip/v3-bigint.in.tfstate similarity index 100% rename from internal/states/statefile/testdata/roundtrip/v3-bigint.in.tfstate rename to states/statefile/testdata/roundtrip/v3-bigint.in.tfstate diff --git a/internal/states/statefile/testdata/roundtrip/v3-bigint.out.tfstate b/states/statefile/testdata/roundtrip/v3-bigint.out.tfstate similarity index 100% rename from internal/states/statefile/testdata/roundtrip/v3-bigint.out.tfstate rename to states/statefile/testdata/roundtrip/v3-bigint.out.tfstate diff --git a/internal/states/statefile/testdata/roundtrip/v3-builtin.in.tfstate b/states/statefile/testdata/roundtrip/v3-builtin.in.tfstate similarity index 100% rename from internal/states/statefile/testdata/roundtrip/v3-builtin.in.tfstate rename to states/statefile/testdata/roundtrip/v3-builtin.in.tfstate diff --git a/internal/states/statefile/testdata/roundtrip/v3-builtin.out.tfstate b/states/statefile/testdata/roundtrip/v3-builtin.out.tfstate similarity index 100% rename from internal/states/statefile/testdata/roundtrip/v3-builtin.out.tfstate rename to states/statefile/testdata/roundtrip/v3-builtin.out.tfstate diff --git a/internal/states/statefile/testdata/roundtrip/v3-grabbag.in.tfstate b/states/statefile/testdata/roundtrip/v3-grabbag.in.tfstate similarity index 100% rename from internal/states/statefile/testdata/roundtrip/v3-grabbag.in.tfstate rename to states/statefile/testdata/roundtrip/v3-grabbag.in.tfstate diff --git a/internal/states/statefile/testdata/roundtrip/v3-grabbag.out.tfstate b/states/statefile/testdata/roundtrip/v3-grabbag.out.tfstate similarity index 100% rename from internal/states/statefile/testdata/roundtrip/v3-grabbag.out.tfstate rename to states/statefile/testdata/roundtrip/v3-grabbag.out.tfstate diff --git a/internal/states/statefile/testdata/roundtrip/v3-invalid-depends.in.tfstate b/states/statefile/testdata/roundtrip/v3-invalid-depends.in.tfstate similarity index 100% rename from internal/states/statefile/testdata/roundtrip/v3-invalid-depends.in.tfstate rename to states/statefile/testdata/roundtrip/v3-invalid-depends.in.tfstate diff --git a/internal/states/statefile/testdata/roundtrip/v3-invalid-depends.out.tfstate b/states/statefile/testdata/roundtrip/v3-invalid-depends.out.tfstate similarity index 100% rename from internal/states/statefile/testdata/roundtrip/v3-invalid-depends.out.tfstate rename to states/statefile/testdata/roundtrip/v3-invalid-depends.out.tfstate diff --git a/internal/states/statefile/testdata/roundtrip/v3-simple.in.tfstate b/states/statefile/testdata/roundtrip/v3-simple.in.tfstate similarity index 100% rename from internal/states/statefile/testdata/roundtrip/v3-simple.in.tfstate rename to states/statefile/testdata/roundtrip/v3-simple.in.tfstate diff --git a/internal/states/statefile/testdata/roundtrip/v3-simple.out.tfstate b/states/statefile/testdata/roundtrip/v3-simple.out.tfstate similarity index 100% rename from internal/states/statefile/testdata/roundtrip/v3-simple.out.tfstate rename to states/statefile/testdata/roundtrip/v3-simple.out.tfstate diff --git a/internal/states/statefile/testdata/roundtrip/v4-cbd.in.tfstate b/states/statefile/testdata/roundtrip/v4-cbd.in.tfstate similarity index 100% rename from internal/states/statefile/testdata/roundtrip/v4-cbd.in.tfstate rename to states/statefile/testdata/roundtrip/v4-cbd.in.tfstate diff --git a/internal/states/statefile/testdata/roundtrip/v4-cbd.out.tfstate b/states/statefile/testdata/roundtrip/v4-cbd.out.tfstate similarity index 100% rename from internal/states/statefile/testdata/roundtrip/v4-cbd.out.tfstate rename to states/statefile/testdata/roundtrip/v4-cbd.out.tfstate diff --git a/internal/states/statefile/testdata/roundtrip/v4-foreach.in.tfstate b/states/statefile/testdata/roundtrip/v4-foreach.in.tfstate similarity index 100% rename from internal/states/statefile/testdata/roundtrip/v4-foreach.in.tfstate rename to states/statefile/testdata/roundtrip/v4-foreach.in.tfstate diff --git a/internal/states/statefile/testdata/roundtrip/v4-foreach.out.tfstate b/states/statefile/testdata/roundtrip/v4-foreach.out.tfstate similarity index 100% rename from internal/states/statefile/testdata/roundtrip/v4-foreach.out.tfstate rename to states/statefile/testdata/roundtrip/v4-foreach.out.tfstate diff --git a/internal/states/statefile/testdata/roundtrip/v4-future.in.tfstate b/states/statefile/testdata/roundtrip/v4-future.in.tfstate similarity index 100% rename from internal/states/statefile/testdata/roundtrip/v4-future.in.tfstate rename to states/statefile/testdata/roundtrip/v4-future.in.tfstate diff --git a/internal/states/statefile/testdata/roundtrip/v4-future.out.tfstate b/states/statefile/testdata/roundtrip/v4-future.out.tfstate similarity index 100% rename from internal/states/statefile/testdata/roundtrip/v4-future.out.tfstate rename to states/statefile/testdata/roundtrip/v4-future.out.tfstate diff --git a/internal/states/statefile/testdata/roundtrip/v4-legacy-foreach.in.tfstate b/states/statefile/testdata/roundtrip/v4-legacy-foreach.in.tfstate similarity index 100% rename from internal/states/statefile/testdata/roundtrip/v4-legacy-foreach.in.tfstate rename to states/statefile/testdata/roundtrip/v4-legacy-foreach.in.tfstate diff --git a/internal/states/statefile/testdata/roundtrip/v4-legacy-foreach.out.tfstate b/states/statefile/testdata/roundtrip/v4-legacy-foreach.out.tfstate similarity index 100% rename from internal/states/statefile/testdata/roundtrip/v4-legacy-foreach.out.tfstate rename to states/statefile/testdata/roundtrip/v4-legacy-foreach.out.tfstate diff --git a/internal/states/statefile/testdata/roundtrip/v4-legacy-modules.in.tfstate b/states/statefile/testdata/roundtrip/v4-legacy-modules.in.tfstate similarity index 100% rename from internal/states/statefile/testdata/roundtrip/v4-legacy-modules.in.tfstate rename to states/statefile/testdata/roundtrip/v4-legacy-modules.in.tfstate diff --git a/internal/states/statefile/testdata/roundtrip/v4-legacy-modules.out.tfstate b/states/statefile/testdata/roundtrip/v4-legacy-modules.out.tfstate similarity index 100% rename from internal/states/statefile/testdata/roundtrip/v4-legacy-modules.out.tfstate rename to states/statefile/testdata/roundtrip/v4-legacy-modules.out.tfstate diff --git a/internal/states/statefile/testdata/roundtrip/v4-legacy-simple.in.tfstate b/states/statefile/testdata/roundtrip/v4-legacy-simple.in.tfstate similarity index 100% rename from internal/states/statefile/testdata/roundtrip/v4-legacy-simple.in.tfstate rename to states/statefile/testdata/roundtrip/v4-legacy-simple.in.tfstate diff --git a/internal/states/statefile/testdata/roundtrip/v4-legacy-simple.out.tfstate b/states/statefile/testdata/roundtrip/v4-legacy-simple.out.tfstate similarity index 100% rename from internal/states/statefile/testdata/roundtrip/v4-legacy-simple.out.tfstate rename to states/statefile/testdata/roundtrip/v4-legacy-simple.out.tfstate diff --git a/internal/states/statefile/testdata/roundtrip/v4-modules.in.tfstate b/states/statefile/testdata/roundtrip/v4-modules.in.tfstate similarity index 100% rename from internal/states/statefile/testdata/roundtrip/v4-modules.in.tfstate rename to states/statefile/testdata/roundtrip/v4-modules.in.tfstate diff --git a/internal/states/statefile/testdata/roundtrip/v4-modules.out.tfstate b/states/statefile/testdata/roundtrip/v4-modules.out.tfstate similarity index 100% rename from internal/states/statefile/testdata/roundtrip/v4-modules.out.tfstate rename to states/statefile/testdata/roundtrip/v4-modules.out.tfstate diff --git a/internal/states/statefile/testdata/roundtrip/v4-simple.in.tfstate b/states/statefile/testdata/roundtrip/v4-simple.in.tfstate similarity index 100% rename from internal/states/statefile/testdata/roundtrip/v4-simple.in.tfstate rename to states/statefile/testdata/roundtrip/v4-simple.in.tfstate diff --git a/internal/states/statefile/testdata/roundtrip/v4-simple.out.tfstate b/states/statefile/testdata/roundtrip/v4-simple.out.tfstate similarity index 100% rename from internal/states/statefile/testdata/roundtrip/v4-simple.out.tfstate rename to states/statefile/testdata/roundtrip/v4-simple.out.tfstate diff --git a/internal/states/statefile/version0.go b/states/statefile/version0.go similarity index 100% rename from internal/states/statefile/version0.go rename to states/statefile/version0.go diff --git a/internal/states/statefile/version1.go b/states/statefile/version1.go similarity index 99% rename from internal/states/statefile/version1.go rename to states/statefile/version1.go index 0b82a13e2290..2a5edc01bd3d 100644 --- a/internal/states/statefile/version1.go +++ b/states/statefile/version1.go @@ -4,7 +4,7 @@ import ( "encoding/json" "fmt" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" ) func readStateV1(src []byte) (*File, tfdiags.Diagnostics) { diff --git a/internal/states/statefile/version1_upgrade.go b/states/statefile/version1_upgrade.go similarity index 100% rename from internal/states/statefile/version1_upgrade.go rename to states/statefile/version1_upgrade.go diff --git a/internal/states/statefile/version2.go b/states/statefile/version2.go similarity index 99% rename from internal/states/statefile/version2.go rename to states/statefile/version2.go index 2c5908c37c09..9f74815ea566 100644 --- a/internal/states/statefile/version2.go +++ b/states/statefile/version2.go @@ -4,7 +4,7 @@ import ( "encoding/json" "fmt" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" ) func readStateV2(src []byte) (*File, tfdiags.Diagnostics) { diff --git a/internal/states/statefile/version2_upgrade.go b/states/statefile/version2_upgrade.go similarity index 100% rename from internal/states/statefile/version2_upgrade.go rename to states/statefile/version2_upgrade.go diff --git a/internal/states/statefile/version3.go b/states/statefile/version3.go similarity index 96% rename from internal/states/statefile/version3.go rename to states/statefile/version3.go index 480cae8f4e1c..ab6414b0a70a 100644 --- a/internal/states/statefile/version3.go +++ b/states/statefile/version3.go @@ -4,7 +4,7 @@ import ( "encoding/json" "fmt" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" ) func readStateV3(src []byte) (*File, tfdiags.Diagnostics) { diff --git a/internal/states/statefile/version3_upgrade.go b/states/statefile/version3_upgrade.go similarity index 98% rename from internal/states/statefile/version3_upgrade.go rename to states/statefile/version3_upgrade.go index f46430af38a0..29c3eb77bc60 100644 --- a/internal/states/statefile/version3_upgrade.go +++ b/states/statefile/version3_upgrade.go @@ -10,10 +10,10 @@ import ( "github.com/zclconf/go-cty/cty" ctyjson "github.com/zclconf/go-cty/cty/json" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/tfdiags" ) func upgradeStateV3ToV4(old *stateV3) (*stateV4, error) { diff --git a/internal/states/statefile/version4.go b/states/statefile/version4.go similarity index 99% rename from internal/states/statefile/version4.go rename to states/statefile/version4.go index 2cdde4be7107..d9ff1ed1361b 100644 --- a/internal/states/statefile/version4.go +++ b/states/statefile/version4.go @@ -10,11 +10,11 @@ import ( "github.com/zclconf/go-cty/cty" ctyjson "github.com/zclconf/go-cty/cty/json" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/checks" - "github.com/hashicorp/terraform/internal/lang/marks" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/checks" + "github.com/hashicorp/terraform/lang/marks" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/tfdiags" ) func readStateV4(src []byte) (*File, tfdiags.Diagnostics) { diff --git a/internal/states/statefile/version4_test.go b/states/statefile/version4_test.go similarity index 99% rename from internal/states/statefile/version4_test.go rename to states/statefile/version4_test.go index d71d33734f05..f097a6069cc5 100644 --- a/internal/states/statefile/version4_test.go +++ b/states/statefile/version4_test.go @@ -5,7 +5,7 @@ import ( "strings" "testing" - "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/hashicorp/terraform/tfdiags" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/states/statefile/write.go b/states/statefile/write.go similarity index 100% rename from internal/states/statefile/write.go rename to states/statefile/write.go diff --git a/internal/states/statemgr/doc.go b/states/statemgr/doc.go similarity index 100% rename from internal/states/statemgr/doc.go rename to states/statemgr/doc.go diff --git a/internal/states/statemgr/filesystem.go b/states/statemgr/filesystem.go similarity index 98% rename from internal/states/statemgr/filesystem.go rename to states/statemgr/filesystem.go index bdfc6832b5dd..c091bd9e7377 100644 --- a/internal/states/statemgr/filesystem.go +++ b/states/statemgr/filesystem.go @@ -14,9 +14,9 @@ import ( multierror "github.com/hashicorp/go-multierror" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/statefile" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/statefile" + "github.com/hashicorp/terraform/terraform" ) // Filesystem is a full state manager that uses a file in the local filesystem diff --git a/internal/states/statemgr/filesystem_lock_unix.go b/states/statemgr/filesystem_lock_unix.go similarity index 100% rename from internal/states/statemgr/filesystem_lock_unix.go rename to states/statemgr/filesystem_lock_unix.go diff --git a/internal/states/statemgr/filesystem_lock_windows.go b/states/statemgr/filesystem_lock_windows.go similarity index 100% rename from internal/states/statemgr/filesystem_lock_windows.go rename to states/statemgr/filesystem_lock_windows.go diff --git a/internal/states/statemgr/filesystem_test.go b/states/statemgr/filesystem_test.go similarity index 98% rename from internal/states/statemgr/filesystem_test.go rename to states/statemgr/filesystem_test.go index 2f6285fbd1ee..53ef2932e6e3 100644 --- a/internal/states/statemgr/filesystem_test.go +++ b/states/statemgr/filesystem_test.go @@ -13,9 +13,9 @@ import ( version "github.com/hashicorp/go-version" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/statefile" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/statefile" tfversion "github.com/hashicorp/terraform/version" ) diff --git a/internal/states/statemgr/helper.go b/states/statemgr/helper.go similarity index 91% rename from internal/states/statemgr/helper.go rename to states/statemgr/helper.go index 6cae85702ea9..d4ba44509662 100644 --- a/internal/states/statemgr/helper.go +++ b/states/statemgr/helper.go @@ -4,9 +4,9 @@ package statemgr // operations done against full state managers. import ( - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/statefile" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/statefile" + "github.com/hashicorp/terraform/terraform" "github.com/hashicorp/terraform/version" ) diff --git a/internal/states/statemgr/lineage.go b/states/statemgr/lineage.go similarity index 100% rename from internal/states/statemgr/lineage.go rename to states/statemgr/lineage.go diff --git a/internal/states/statemgr/lock.go b/states/statemgr/lock.go similarity index 90% rename from internal/states/statemgr/lock.go rename to states/statemgr/lock.go index 863dc2f0dd18..0aeda6d8ecc5 100644 --- a/internal/states/statemgr/lock.go +++ b/states/statemgr/lock.go @@ -1,8 +1,8 @@ package statemgr import ( - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/terraform" ) // LockDisabled implements State and Locker but disables state locking. diff --git a/internal/states/statemgr/lock_test.go b/states/statemgr/lock_test.go similarity index 100% rename from internal/states/statemgr/lock_test.go rename to states/statemgr/lock_test.go diff --git a/internal/states/statemgr/locker.go b/states/statemgr/locker.go similarity index 100% rename from internal/states/statemgr/locker.go rename to states/statemgr/locker.go diff --git a/internal/states/statemgr/migrate.go b/states/statemgr/migrate.go similarity index 99% rename from internal/states/statemgr/migrate.go rename to states/statemgr/migrate.go index 099e26a88e74..9b55fe9a7016 100644 --- a/internal/states/statemgr/migrate.go +++ b/states/statemgr/migrate.go @@ -3,7 +3,7 @@ package statemgr import ( "fmt" - "github.com/hashicorp/terraform/internal/states/statefile" + "github.com/hashicorp/terraform/states/statefile" ) // Migrator is an optional interface implemented by state managers that diff --git a/internal/states/statemgr/migrate_test.go b/states/statemgr/migrate_test.go similarity index 95% rename from internal/states/statemgr/migrate_test.go rename to states/statemgr/migrate_test.go index e9269a177039..0cf2113a252e 100644 --- a/internal/states/statemgr/migrate_test.go +++ b/states/statemgr/migrate_test.go @@ -5,9 +5,9 @@ import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/statefile" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/statefile" ) func TestCheckValidImport(t *testing.T) { diff --git a/internal/states/statemgr/persistent.go b/states/statemgr/persistent.go similarity index 97% rename from internal/states/statemgr/persistent.go rename to states/statemgr/persistent.go index 70d709f85f4e..852015887968 100644 --- a/internal/states/statemgr/persistent.go +++ b/states/statemgr/persistent.go @@ -3,8 +3,8 @@ package statemgr import ( version "github.com/hashicorp/go-version" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/terraform" ) // Persistent is a union of the Refresher and Persistent interfaces, for types diff --git a/internal/states/statemgr/plan.go b/states/statemgr/plan.go similarity index 96% rename from internal/states/statemgr/plan.go rename to states/statemgr/plan.go index fb42df31295f..b5036030a640 100644 --- a/internal/states/statemgr/plan.go +++ b/states/statemgr/plan.go @@ -3,8 +3,8 @@ package statemgr import ( "fmt" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/statefile" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/statefile" ) // PlannedStateUpdate is a special helper to obtain a statefile representation diff --git a/internal/states/statemgr/snapshotmetarel_string.go b/states/statemgr/snapshotmetarel_string.go similarity index 100% rename from internal/states/statemgr/snapshotmetarel_string.go rename to states/statemgr/snapshotmetarel_string.go diff --git a/internal/states/statemgr/statemgr.go b/states/statemgr/statemgr.go similarity index 100% rename from internal/states/statemgr/statemgr.go rename to states/statemgr/statemgr.go diff --git a/internal/states/statemgr/statemgr_fake.go b/states/statemgr/statemgr_fake.go similarity index 97% rename from internal/states/statemgr/statemgr_fake.go rename to states/statemgr/statemgr_fake.go index 985e6c677517..95a0449e236b 100644 --- a/internal/states/statemgr/statemgr_fake.go +++ b/states/statemgr/statemgr_fake.go @@ -4,8 +4,8 @@ import ( "errors" "sync" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/terraform" ) // NewFullFake returns a full state manager that really only supports transient diff --git a/internal/states/statemgr/statemgr_test.go b/states/statemgr/statemgr_test.go similarity index 97% rename from internal/states/statemgr/statemgr_test.go rename to states/statemgr/statemgr_test.go index e9e8226712c2..a49781208ea4 100644 --- a/internal/states/statemgr/statemgr_test.go +++ b/states/statemgr/statemgr_test.go @@ -8,7 +8,7 @@ import ( "testing" "time" - _ "github.com/hashicorp/terraform/internal/logging" + _ "github.com/hashicorp/terraform/logging" ) func TestNewLockInfo(t *testing.T) { diff --git a/internal/states/statemgr/testdata/lockstate.go b/states/statemgr/testdata/lockstate.go similarity index 88% rename from internal/states/statemgr/testdata/lockstate.go rename to states/statemgr/testdata/lockstate.go index a353900cfa9a..f0b336068f35 100644 --- a/internal/states/statemgr/testdata/lockstate.go +++ b/states/statemgr/testdata/lockstate.go @@ -5,7 +5,7 @@ import ( "log" "os" - "github.com/hashicorp/terraform/internal/states/statemgr" + "github.com/hashicorp/terraform/states/statemgr" ) // Attempt to open and lock a terraform state file. diff --git a/internal/states/statemgr/testing.go b/states/statemgr/testing.go similarity index 96% rename from internal/states/statemgr/testing.go rename to states/statemgr/testing.go index eabf46dc0e40..584122473c81 100644 --- a/internal/states/statemgr/testing.go +++ b/states/statemgr/testing.go @@ -7,9 +7,9 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/states" - "github.com/hashicorp/terraform/internal/states/statefile" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/states/statefile" ) // TestFull is a helper for testing full state manager implementations. It diff --git a/internal/states/statemgr/transient.go b/states/statemgr/transient.go similarity index 98% rename from internal/states/statemgr/transient.go rename to states/statemgr/transient.go index e47683e98bb3..c62297754b2c 100644 --- a/internal/states/statemgr/transient.go +++ b/states/statemgr/transient.go @@ -1,6 +1,6 @@ package statemgr -import "github.com/hashicorp/terraform/internal/states" +import "github.com/hashicorp/terraform/states" // Transient is a union of the Reader and Writer interfaces, for types that // deal with transient snapshots. diff --git a/internal/states/statemgr/transient_inmem.go b/states/statemgr/transient_inmem.go similarity index 94% rename from internal/states/statemgr/transient_inmem.go rename to states/statemgr/transient_inmem.go index 4692225cb54d..07fd3726f560 100644 --- a/internal/states/statemgr/transient_inmem.go +++ b/states/statemgr/transient_inmem.go @@ -3,7 +3,7 @@ package statemgr import ( "sync" - "github.com/hashicorp/terraform/internal/states" + "github.com/hashicorp/terraform/states" ) // NewTransientInMemory returns a Transient implementation that retains diff --git a/internal/states/sync.go b/states/sync.go similarity index 99% rename from internal/states/sync.go rename to states/sync.go index d48fa755189c..6541cc22a769 100644 --- a/internal/states/sync.go +++ b/states/sync.go @@ -4,8 +4,8 @@ import ( "log" "sync" - "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/checks" + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/checks" "github.com/zclconf/go-cty/cty" ) diff --git a/internal/terminal/impl_others.go b/terminal/impl_others.go similarity index 100% rename from internal/terminal/impl_others.go rename to terminal/impl_others.go diff --git a/internal/terminal/impl_windows.go b/terminal/impl_windows.go similarity index 100% rename from internal/terminal/impl_windows.go rename to terminal/impl_windows.go diff --git a/internal/terminal/stream.go b/terminal/stream.go similarity index 100% rename from internal/terminal/stream.go rename to terminal/stream.go diff --git a/internal/terminal/streams.go b/terminal/streams.go similarity index 100% rename from internal/terminal/streams.go rename to terminal/streams.go diff --git a/internal/terminal/streams_test.go b/terminal/streams_test.go similarity index 100% rename from internal/terminal/streams_test.go rename to terminal/streams_test.go diff --git a/internal/terminal/testing.go b/terminal/testing.go similarity index 100% rename from internal/terminal/testing.go rename to terminal/testing.go diff --git a/internal/tfdiags/config_traversals.go b/tfdiags/config_traversals.go similarity index 100% rename from internal/tfdiags/config_traversals.go rename to tfdiags/config_traversals.go diff --git a/internal/tfdiags/consolidate_warnings.go b/tfdiags/consolidate_warnings.go similarity index 100% rename from internal/tfdiags/consolidate_warnings.go rename to tfdiags/consolidate_warnings.go diff --git a/internal/tfdiags/consolidate_warnings_test.go b/tfdiags/consolidate_warnings_test.go similarity index 92% rename from internal/tfdiags/consolidate_warnings_test.go rename to tfdiags/consolidate_warnings_test.go index df94d4af8f90..4d3e1f0b60aa 100644 --- a/internal/tfdiags/consolidate_warnings_test.go +++ b/tfdiags/consolidate_warnings_test.go @@ -56,7 +56,7 @@ func TestConsolidateWarnings(t *testing.T) { got := diags.ConsolidateWarnings(2).ForRPC() want := Diagnostics{ // First set - &rpcFriendlyDiag{ + &rpcFriendlyDiagTF{ Severity_: Warning, Summary_: "Warning 1", Detail_: "This one has a subject 0", @@ -66,7 +66,7 @@ func TestConsolidateWarnings(t *testing.T) { End: SourcePos{Line: 1, Column: 1, Byte: 0}, }, }, - &rpcFriendlyDiag{ + &rpcFriendlyDiagTF{ Severity_: Error, Summary_: "Error 1", Detail_: "This one has a subject 0", @@ -76,18 +76,18 @@ func TestConsolidateWarnings(t *testing.T) { End: SourcePos{Line: 1, Column: 1, Byte: 0}, }, }, - &rpcFriendlyDiag{ + &rpcFriendlyDiagTF{ Severity_: Warning, Summary_: "Warning 2", Detail_: "This one is sourceless 0", }, - &rpcFriendlyDiag{ + &rpcFriendlyDiagTF{ Severity_: Warning, Summary_: "Warning 3", }, // Second set (consolidation begins; note additional paragraph in Warning 1 detail) - &rpcFriendlyDiag{ + &rpcFriendlyDiagTF{ Severity_: Warning, Summary_: "Warning 1", Detail_: "This one has a subject 1\n\n(and 2 more similar warnings elsewhere)", @@ -97,7 +97,7 @@ func TestConsolidateWarnings(t *testing.T) { End: SourcePos{Line: 1, Column: 1, Byte: 0}, }, }, - &rpcFriendlyDiag{ + &rpcFriendlyDiagTF{ Severity_: Error, Summary_: "Error 1", Detail_: "This one has a subject 1", @@ -107,18 +107,18 @@ func TestConsolidateWarnings(t *testing.T) { End: SourcePos{Line: 1, Column: 1, Byte: 0}, }, }, - &rpcFriendlyDiag{ + &rpcFriendlyDiagTF{ Severity_: Warning, Summary_: "Warning 2", Detail_: "This one is sourceless 1", }, - &rpcFriendlyDiag{ + &rpcFriendlyDiagTF{ Severity_: Warning, Summary_: "Warning 3", }, // Third set (no more Warning 1, because it's consolidated) - &rpcFriendlyDiag{ + &rpcFriendlyDiagTF{ Severity_: Error, Summary_: "Error 1", Detail_: "This one has a subject 2", @@ -128,18 +128,18 @@ func TestConsolidateWarnings(t *testing.T) { End: SourcePos{Line: 1, Column: 1, Byte: 0}, }, }, - &rpcFriendlyDiag{ + &rpcFriendlyDiagTF{ Severity_: Warning, Summary_: "Warning 2", Detail_: "This one is sourceless 2", }, - &rpcFriendlyDiag{ + &rpcFriendlyDiagTF{ Severity_: Warning, Summary_: "Warning 3", }, // Fourth set (still no warning 1) - &rpcFriendlyDiag{ + &rpcFriendlyDiagTF{ Severity_: Error, Summary_: "Error 1", Detail_: "This one has a subject 3", @@ -149,19 +149,19 @@ func TestConsolidateWarnings(t *testing.T) { End: SourcePos{Line: 1, Column: 1, Byte: 0}, }, }, - &rpcFriendlyDiag{ + &rpcFriendlyDiagTF{ Severity_: Warning, Summary_: "Warning 2", Detail_: "This one is sourceless 3", }, - &rpcFriendlyDiag{ + &rpcFriendlyDiagTF{ Severity_: Warning, Summary_: "Warning 3", }, // Special straggler warning gets to show up unconsolidated, because // there is only one of it. - &rpcFriendlyDiag{ + &rpcFriendlyDiagTF{ Severity_: Warning, Summary_: "Warning 4", Detail_: "Only one of this one", diff --git a/internal/tfdiags/contextual.go b/tfdiags/contextual.go similarity index 100% rename from internal/tfdiags/contextual.go rename to tfdiags/contextual.go diff --git a/internal/tfdiags/contextual_test.go b/tfdiags/contextual_test.go similarity index 100% rename from internal/tfdiags/contextual_test.go rename to tfdiags/contextual_test.go diff --git a/internal/tfdiags/diagnostic.go b/tfdiags/diagnostic.go similarity index 100% rename from internal/tfdiags/diagnostic.go rename to tfdiags/diagnostic.go diff --git a/internal/tfdiags/diagnostic_base.go b/tfdiags/diagnostic_base.go similarity index 100% rename from internal/tfdiags/diagnostic_base.go rename to tfdiags/diagnostic_base.go diff --git a/internal/tfdiags/diagnostic_extra.go b/tfdiags/diagnostic_extra.go similarity index 100% rename from internal/tfdiags/diagnostic_extra.go rename to tfdiags/diagnostic_extra.go diff --git a/internal/tfdiags/diagnostics.go b/tfdiags/diagnostics.go similarity index 100% rename from internal/tfdiags/diagnostics.go rename to tfdiags/diagnostics.go diff --git a/internal/tfdiags/diagnostics_test.go b/tfdiags/diagnostics_test.go similarity index 100% rename from internal/tfdiags/diagnostics_test.go rename to tfdiags/diagnostics_test.go diff --git a/internal/tfdiags/doc.go b/tfdiags/doc.go similarity index 100% rename from internal/tfdiags/doc.go rename to tfdiags/doc.go diff --git a/internal/tfdiags/error.go b/tfdiags/error.go similarity index 100% rename from internal/tfdiags/error.go rename to tfdiags/error.go diff --git a/internal/tfdiags/hcl.go b/tfdiags/hcl.go similarity index 100% rename from internal/tfdiags/hcl.go rename to tfdiags/hcl.go diff --git a/internal/tfdiags/hcl_test.go b/tfdiags/hcl_test.go similarity index 100% rename from internal/tfdiags/hcl_test.go rename to tfdiags/hcl_test.go diff --git a/internal/tfdiags/rpc_friendly.go b/tfdiags/rpc_friendly.go similarity index 69% rename from internal/tfdiags/rpc_friendly.go rename to tfdiags/rpc_friendly.go index 4c627bf98aac..e8a7a42e6fc3 100644 --- a/internal/tfdiags/rpc_friendly.go +++ b/tfdiags/rpc_friendly.go @@ -4,7 +4,7 @@ import ( "encoding/gob" ) -type rpcFriendlyDiag struct { +type rpcFriendlyDiagTF struct { Severity_ Severity Summary_ string Detail_ string @@ -12,7 +12,7 @@ type rpcFriendlyDiag struct { Context_ *SourceRange } -// rpcFriendlyDiag transforms a given diagnostic so that is more friendly to +// rpcFriendlyDiagTF transforms a given diagnostic so that is more friendly to // RPC. // // In particular, it currently returns an object that can be serialized and @@ -21,7 +21,7 @@ type rpcFriendlyDiag struct { func makeRPCFriendlyDiag(diag Diagnostic) Diagnostic { desc := diag.Description() source := diag.Source() - return &rpcFriendlyDiag{ + return &rpcFriendlyDiagTF{ Severity_: diag.Severity(), Summary_: desc.Summary, Detail_: desc.Detail, @@ -30,35 +30,35 @@ func makeRPCFriendlyDiag(diag Diagnostic) Diagnostic { } } -func (d *rpcFriendlyDiag) Severity() Severity { +func (d *rpcFriendlyDiagTF) Severity() Severity { return d.Severity_ } -func (d *rpcFriendlyDiag) Description() Description { +func (d *rpcFriendlyDiagTF) Description() Description { return Description{ Summary: d.Summary_, Detail: d.Detail_, } } -func (d *rpcFriendlyDiag) Source() Source { +func (d *rpcFriendlyDiagTF) Source() Source { return Source{ Subject: d.Subject_, Context: d.Context_, } } -func (d rpcFriendlyDiag) FromExpr() *FromExpr { +func (d rpcFriendlyDiagTF) FromExpr() *FromExpr { // RPC-friendly diagnostics cannot preserve expression information because // expressions themselves are not RPC-friendly. return nil } -func (d rpcFriendlyDiag) ExtraInfo() interface{} { +func (d rpcFriendlyDiagTF) ExtraInfo() interface{} { // RPC-friendly diagnostics always discard any "extra information". return nil } func init() { - gob.Register((*rpcFriendlyDiag)(nil)) + gob.Register((*rpcFriendlyDiagTF)(nil)) } diff --git a/internal/tfdiags/rpc_friendly_test.go b/tfdiags/rpc_friendly_test.go similarity index 95% rename from internal/tfdiags/rpc_friendly_test.go rename to tfdiags/rpc_friendly_test.go index bf5170753950..e9009e93cfd0 100644 --- a/internal/tfdiags/rpc_friendly_test.go +++ b/tfdiags/rpc_friendly_test.go @@ -45,15 +45,15 @@ func TestDiagnosticsForRPC(t *testing.T) { } want := Diagnostics{ - &rpcFriendlyDiag{ + &rpcFriendlyDiagTF{ Severity_: Error, Summary_: "bad", }, - &rpcFriendlyDiag{ + &rpcFriendlyDiagTF{ Severity_: Warning, Summary_: "less bad", }, - &rpcFriendlyDiag{ + &rpcFriendlyDiagTF{ Severity_: Error, Summary_: "bad bad bad", Detail_: "badily bad bad", diff --git a/internal/tfdiags/severity_string.go b/tfdiags/severity_string.go similarity index 100% rename from internal/tfdiags/severity_string.go rename to tfdiags/severity_string.go diff --git a/internal/tfdiags/simple_warning.go b/tfdiags/simple_warning.go similarity index 100% rename from internal/tfdiags/simple_warning.go rename to tfdiags/simple_warning.go diff --git a/internal/tfdiags/source_range.go b/tfdiags/source_range.go similarity index 100% rename from internal/tfdiags/source_range.go rename to tfdiags/source_range.go diff --git a/internal/tfdiags/sourceless.go b/tfdiags/sourceless.go similarity index 100% rename from internal/tfdiags/sourceless.go rename to tfdiags/sourceless.go diff --git a/internal/tfplugin5/tfplugin5.pb.go b/tfplugin5/tfplugin5.pb.go similarity index 100% rename from internal/tfplugin5/tfplugin5.pb.go rename to tfplugin5/tfplugin5.pb.go diff --git a/internal/tfplugin5/tfplugin5.proto b/tfplugin5/tfplugin5.proto similarity index 100% rename from internal/tfplugin5/tfplugin5.proto rename to tfplugin5/tfplugin5.proto diff --git a/internal/tfplugin6/tfplugin6.pb.go b/tfplugin6/tfplugin6.pb.go similarity index 100% rename from internal/tfplugin6/tfplugin6.pb.go rename to tfplugin6/tfplugin6.pb.go diff --git a/internal/tfplugin6/tfplugin6.proto b/tfplugin6/tfplugin6.proto similarity index 100% rename from internal/tfplugin6/tfplugin6.proto rename to tfplugin6/tfplugin6.proto diff --git a/working_dir.go b/working_dir.go index 6d9945c0c5f5..da24627848ac 100644 --- a/working_dir.go +++ b/working_dir.go @@ -1,6 +1,6 @@ package main -import "github.com/hashicorp/terraform/internal/command/workdir" +import "github.com/hashicorp/terraform/command/workdir" func WorkingDir(originalDir string, overrideDataDir string) *workdir.Dir { ret := workdir.NewDir(".") // caller should already have used os.Chdir in "-chdir=..." mode