check for duplicate import blocks (#33190)

Importing to the same target address twice or importing the same ID
to multiple different resources of the same type is not allowed.
This commit is contained in:
CJ Horton 2023-05-12 15:14:44 -07:00 committed by GitHub
parent d5fed58fc5
commit bd6ba6cf99
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 143 additions and 0 deletions

View File

@ -0,0 +1,15 @@
resource "aws_instance" "web" {
}
resource "aws_instance" "other_web" {
}
import {
to = aws_instance.web
id = "test"
}
import {
to = aws_instance.other_web
id = "test"
}

View File

@ -0,0 +1,34 @@
{
"format_version": "1.0",
"valid": false,
"error_count": 1,
"warning_count": 0,
"diagnostics": [
{
"severity": "error",
"summary": "Duplicate import for ID \"test\"",
"detail": "An import block for the ID \"test\" and a resource of type \"aws_instance\" was already declared at testdata/validate-invalid/duplicate_import_ids/main.tf:7,1-7. The same resource cannot be imported twice.",
"range": {
"filename": "testdata/validate-invalid/duplicate_import_ids/main.tf",
"start": {
"line": 12,
"column": 1,
"byte": 126
},
"end": {
"line": 12,
"column": 7,
"byte": 132
}
},
"snippet": {
"context": null,
"code": "import {",
"start_line": 12,
"highlight_start_offset": 0,
"highlight_end_offset": 6,
"values": []
}
}
]
}

View File

@ -0,0 +1,12 @@
resource "aws_instance" "web" {
}
import {
to = aws_instance.web
id = "test"
}
import {
to = aws_instance.web
id = "test2"
}

View File

@ -0,0 +1,34 @@
{
"format_version": "1.0",
"valid": false,
"error_count": 1,
"warning_count": 0,
"diagnostics": [
{
"severity": "error",
"summary": "Duplicate import configuration for \"aws_instance.web\"",
"detail": "An import block for the resource \"aws_instance.web\" was already declared at testdata/validate-invalid/duplicate_import_targets/main.tf:4,1-7. A resource can have only one import block.",
"range": {
"filename": "testdata/validate-invalid/duplicate_import_targets/main.tf",
"start": {
"line": 9,
"column": 1,
"byte": 85
},
"end": {
"line": 9,
"column": 7,
"byte": 91
}
},
"snippet": {
"context": null,
"code": "import {",
"start_line": 9,
"highlight_start_offset": 0,
"highlight_end_offset": 6,
"values": []
}
}
]
}

View File

@ -150,6 +150,28 @@ func TestSameResourceMultipleTimesShouldFail(t *testing.T) {
}
}
func TestSameImportTargetMultipleTimesShouldFail(t *testing.T) {
output, code := setupTest(t, "validate-invalid/duplicate_import_targets")
if code != 1 {
t.Fatalf("Should have failed: %d\n\n%s", code, output.Stderr())
}
wantError := `Error: Duplicate import configuration for "aws_instance.web"`
if !strings.Contains(output.Stderr(), wantError) {
t.Fatalf("Missing error string %q\n\n'%s'", wantError, output.Stderr())
}
}
func TestSameImportIDMultipleTimesShouldFail(t *testing.T) {
output, code := setupTest(t, "validate-invalid/duplicate_import_ids")
if code != 1 {
t.Fatalf("Should have failed: %d\n\n%s", code, output.Stderr())
}
wantError := `Error: Duplicate import for ID "test"`
if !strings.Contains(output.Stderr(), wantError) {
t.Fatalf("Missing error string %q\n\n'%s'", wantError, output.Stderr())
}
}
func TestOutputWithoutValueShouldFail(t *testing.T) {
output, code := setupTest(t, "validate-invalid/outputs")
if code != 1 {
@ -218,6 +240,8 @@ func TestValidate_json(t *testing.T) {
{"validate-invalid/multiple_providers", false},
{"validate-invalid/multiple_modules", false},
{"validate-invalid/multiple_resources", false},
{"validate-invalid/duplicate_import_targets", false},
{"validate-invalid/duplicate_import_ids", false},
{"validate-invalid/outputs", false},
{"validate-invalid/incorrectmodulename", false},
{"validate-invalid/interpolation", false},

View File

@ -403,6 +403,30 @@ func (m *Module) appendFile(file *File) hcl.Diagnostics {
}
for _, i := range file.Import {
for _, mi := range m.Import {
if i.To.Equal(mi.To) {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: fmt.Sprintf("Duplicate import configuration for %q", i.To),
Detail: fmt.Sprintf("An import block for the resource %q was already declared at %s. A resource can have only one import block.", i.To, mi.DeclRange),
Subject: &i.DeclRange,
})
continue
}
if i.ID == mi.ID {
if i.To.Resource.Resource.Type == mi.To.Resource.Resource.Type {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: fmt.Sprintf("Duplicate import for ID %q", i.ID),
Detail: fmt.Sprintf("An import block for the ID %q and a resource of type %q was already declared at %s. The same resource cannot be imported twice.", i.ID, i.To.Resource.Resource.Type, mi.DeclRange),
Subject: &i.DeclRange,
})
continue
}
}
}
if i.ProviderConfigRef != nil {
i.Provider = m.ProviderForLocalConfig(addrs.LocalProviderConfig{
LocalName: i.ProviderConfigRef.Name,