Skip to content

Commit b7f56d1

Browse files
authored
fix: state drift of "stackit_server" (#679)
* fix: State drift of "stackit_server" when using "stackit_server_network_interface_attach" * fix: tests * add acceptance tests for stackit_server_network_interface_attach
1 parent 3e8dcc5 commit b7f56d1

File tree

3 files changed

+172
-22
lines changed

3 files changed

+172
-22
lines changed

stackit/internal/services/iaas/iaas_acc_test.go

Lines changed: 134 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
const (
2020
serverMachineType = "t1.1"
2121
updatedServerMachineType = "t1.2"
22+
nicAttachTfName = "second_network_interface"
2223
)
2324

2425
// Network resource data
@@ -53,6 +54,7 @@ var networkInterfaceResource = map[string]string{
5354
"project_id": testutil.ProjectId,
5455
"network_id": networkResource["network_id"],
5556
"name": "name",
57+
"tfName": "network_interface",
5658
}
5759

5860
// Volume resource data
@@ -200,14 +202,15 @@ func networkAreaRouteResourceConfig(labelValue string) string {
200202
)
201203
}
202204

203-
func networkInterfaceResourceConfig(name string) string {
205+
func networkInterfaceResourceConfig(resourceName, name string) string {
204206
return fmt.Sprintf(`
205-
resource "stackit_network_interface" "network_interface" {
207+
resource "stackit_network_interface" "%s" {
206208
project_id = stackit_network.network.project_id
207209
network_id = stackit_network.network.network_id
208210
name = "%s"
209211
}
210212
`,
213+
resourceName,
211214
name,
212215
)
213216
}
@@ -355,6 +358,19 @@ func imageResourceConfig(name string) string {
355358
)
356359
}
357360

361+
func networkInterfaceAttachmentResourceConfig(nicTfName string) string {
362+
return fmt.Sprintf(`
363+
resource "stackit_server_network_interface_attach" "attach_nic" {
364+
project_id = "%s"
365+
server_id = stackit_server.server.server_id
366+
network_interface_id = stackit_network_interface.%s.network_interface_id
367+
}
368+
`,
369+
testutil.ProjectId,
370+
nicTfName,
371+
)
372+
}
373+
358374
func testAccNetworkAreaConfig(areaname, networkranges, routeLabelValue string) string {
359375
return fmt.Sprintf("%s\n\n%s\n\n%s",
360376
testutil.IaaSProviderConfig(),
@@ -370,13 +386,15 @@ func testAccVolumeConfig(name, size string) string {
370386
)
371387
}
372388

373-
func testAccServerConfig(name, nameservers, serverName, machineType, interfacename string) string {
374-
return fmt.Sprintf("%s\n\n%s\n\n%s\n\n%s\n\n%s\n\n%s\n\n%s",
389+
func testAccServerConfig(name, nameservers, serverName, machineType, nicTfName, interfacename string) string {
390+
return fmt.Sprintf("%s\n\n%s\n\n%s\n\n%s\n\n%s\n\n%s\n\n%s\n\n%s\n\n%s",
375391
testutil.IaaSProviderConfig(),
376392
networkResourceConfig(name, nameservers),
377393
serverResourceConfig(serverName, machineType),
378394
volumeResourceConfig(volumeResource["name"], volumeResource["size"]),
379-
networkInterfaceResourceConfig(interfacename),
395+
networkInterfaceResourceConfig(nicTfName, interfacename),
396+
networkInterfaceResourceConfig(nicAttachTfName, fmt.Sprintf("%s-%s", interfacename, nicAttachTfName)),
397+
networkInterfaceAttachmentResourceConfig(nicAttachTfName),
380398
volumeAttachmentResourceConfig(),
381399
serviceAccountAttachmentResourceConfig(),
382400
)
@@ -390,11 +408,11 @@ func resourceConfigSecurityGroup(name, direction string) string {
390408
)
391409
}
392410

393-
func testAccPublicIpConfig(nameNetwork, nameservers, nameNetworkInterface, publicIpResourceConfig string) string {
411+
func testAccPublicIpConfig(nameNetwork, nameservers, nicTfName, nameNetworkInterface, publicIpResourceConfig string) string {
394412
return fmt.Sprintf("%s\n\n%s\n\n%s\n\n%s",
395413
testutil.IaaSProviderConfig(),
396414
networkResourceConfigRouted(nameNetwork, nameservers),
397-
networkInterfaceResourceConfig(nameNetworkInterface),
415+
networkInterfaceResourceConfig(nicTfName, nameNetworkInterface),
398416
publicIpResourceConfig,
399417
)
400418
}
@@ -659,6 +677,7 @@ func TestAccVolume(t *testing.T) {
659677
}
660678

661679
func TestAccServer(t *testing.T) {
680+
networkInterfaceSecSchemaName := fmt.Sprintf("stackit_network_interface.%s", nicAttachTfName)
662681
resource.Test(t, resource.TestCase{
663682
ProtoV6ProviderFactories: testutil.TestAccProtoV6ProviderFactories,
664683
CheckDestroy: testAccCheckServerDestroy,
@@ -674,6 +693,7 @@ func TestAccServer(t *testing.T) {
674693
),
675694
serverResource["name"],
676695
serverResource["machine_type"],
696+
networkInterfaceResource["tfName"],
677697
networkInterfaceResource["name"],
678698
),
679699
Check: resource.ComposeAggregateTestCheckFunc(
@@ -697,6 +717,9 @@ func TestAccServer(t *testing.T) {
697717
resource.TestCheckResourceAttr("stackit_server.server", "labels.label1", serverResource["label1"]),
698718
resource.TestCheckResourceAttr("stackit_server.server", "user_data", serverResource["user_data"]),
699719
resource.TestCheckResourceAttrSet("stackit_server.server", "network_interfaces.0"),
720+
// The network interface which was attached by "stackit_server_network_interface_attach" should not appear here
721+
resource.TestCheckResourceAttr("stackit_server.server", "network_interfaces.#", "1"),
722+
resource.TestCheckNoResourceAttr("stackit_server.server", "network_interfaces.1"),
700723
resource.TestCheckResourceAttr("stackit_server.server", "boot_volume.size", serverResource["size"]),
701724
resource.TestCheckResourceAttr("stackit_server.server", "boot_volume.source_type", serverResource["source_type"]),
702725
resource.TestCheckResourceAttr("stackit_server.server", "boot_volume.source_id", serverResource["source_id"]),
@@ -714,6 +737,35 @@ func TestAccServer(t *testing.T) {
714737
resource.TestCheckResourceAttrSet("stackit_network_interface.network_interface", "network_interface_id"),
715738
resource.TestCheckResourceAttr("stackit_network_interface.network_interface", "name", networkInterfaceResource["name"]),
716739

740+
// Network Interface second
741+
resource.TestCheckResourceAttrPair(
742+
networkInterfaceSecSchemaName, "project_id",
743+
"stackit_network.network", "project_id",
744+
),
745+
resource.TestCheckResourceAttrPair(
746+
networkInterfaceSecSchemaName, "network_id",
747+
"stackit_network.network", "network_id",
748+
),
749+
resource.TestCheckResourceAttrSet(networkInterfaceSecSchemaName, "network_interface_id"),
750+
resource.TestCheckResourceAttr(
751+
networkInterfaceSecSchemaName, "name",
752+
fmt.Sprintf("%s-%s", networkInterfaceResource["name"], nicAttachTfName),
753+
),
754+
755+
// Network Interface Attachment
756+
resource.TestCheckResourceAttrPair(
757+
"stackit_server_network_interface_attach.attach_nic", "project_id",
758+
"stackit_network.network", "project_id",
759+
),
760+
resource.TestCheckResourceAttrPair(
761+
"stackit_server_network_interface_attach.attach_nic", "server_id",
762+
"stackit_server.server", "server_id",
763+
),
764+
resource.TestCheckResourceAttrPair(
765+
"stackit_server_network_interface_attach.attach_nic", "network_interface_id",
766+
networkInterfaceSecSchemaName, "network_interface_id",
767+
),
768+
717769
// Volume attachment
718770
resource.TestCheckResourceAttrPair(
719771
"stackit_server_volume_attach.attach_volume", "project_id",
@@ -768,6 +820,7 @@ func TestAccServer(t *testing.T) {
768820
),
769821
serverResource["name"],
770822
serverResource["machine_type"],
823+
networkInterfaceResource["tfName"],
771824
networkInterfaceResource["name"],
772825
),
773826
),
@@ -840,7 +893,7 @@ func TestAccServer(t *testing.T) {
840893
},
841894
ImportState: true,
842895
ImportStateVerify: true,
843-
ImportStateVerifyIgnore: []string{"boot_volume", "user_data"}, // Field is not mapped as it is only relevant on creation
896+
ImportStateVerifyIgnore: []string{"boot_volume", "user_data", "network_interfaces"}, // Field is not mapped as it is only relevant on creation
844897
},
845898
{
846899
ResourceName: "stackit_network_interface.network_interface",
@@ -862,6 +915,46 @@ func TestAccServer(t *testing.T) {
862915
ImportState: true,
863916
ImportStateVerify: true,
864917
},
918+
{
919+
ResourceName: networkInterfaceSecSchemaName,
920+
ImportStateIdFunc: func(s *terraform.State) (string, error) {
921+
r, ok := s.RootModule().Resources[networkInterfaceSecSchemaName]
922+
if !ok {
923+
return "", fmt.Errorf("couldn't find resource stackit_network_interface.%s", nicAttachTfName)
924+
}
925+
networkId, ok := r.Primary.Attributes["network_id"]
926+
if !ok {
927+
return "", fmt.Errorf("couldn't find attribute network_id")
928+
}
929+
networkInterfaceId, ok := r.Primary.Attributes["network_interface_id"]
930+
if !ok {
931+
return "", fmt.Errorf("couldn't find attribute network_interface_id")
932+
}
933+
return fmt.Sprintf("%s,%s,%s", testutil.ProjectId, networkId, networkInterfaceId), nil
934+
},
935+
ImportState: true,
936+
ImportStateVerify: true,
937+
},
938+
{
939+
ResourceName: "stackit_server_network_interface_attach.attach_nic",
940+
ImportStateIdFunc: func(s *terraform.State) (string, error) {
941+
r, ok := s.RootModule().Resources["stackit_server_network_interface_attach.attach_nic"]
942+
if !ok {
943+
return "", fmt.Errorf("couldn't find resource stackit_network_interface.%s", nicAttachTfName)
944+
}
945+
serverId, ok := r.Primary.Attributes["server_id"]
946+
if !ok {
947+
return "", fmt.Errorf("couldn't find attribute network_id")
948+
}
949+
networkInterfaceId, ok := r.Primary.Attributes["network_interface_id"]
950+
if !ok {
951+
return "", fmt.Errorf("couldn't find attribute network_interface_id")
952+
}
953+
return fmt.Sprintf("%s,%s,%s", testutil.ProjectId, serverId, networkInterfaceId), nil
954+
},
955+
ImportState: true,
956+
ImportStateVerify: false,
957+
},
865958
{
866959
ResourceName: "stackit_server_volume_attach.attach_volume",
867960
ImportStateIdFunc: func(s *terraform.State) (string, error) {
@@ -913,6 +1006,7 @@ func TestAccServer(t *testing.T) {
9131006
),
9141007
fmt.Sprintf("%s-updated", serverResource["name"]),
9151008
updatedServerMachineType,
1009+
networkInterfaceResource["tfName"],
9161010
fmt.Sprintf("%s-updated", networkInterfaceResource["name"]),
9171011
),
9181012
Check: resource.ComposeAggregateTestCheckFunc(
@@ -950,6 +1044,35 @@ func TestAccServer(t *testing.T) {
9501044
),
9511045
resource.TestCheckResourceAttrSet("stackit_network_interface.network_interface", "network_interface_id"),
9521046
resource.TestCheckResourceAttr("stackit_network_interface.network_interface", "name", fmt.Sprintf("%s-updated", networkInterfaceResource["name"])),
1047+
1048+
// Network Interface second
1049+
resource.TestCheckResourceAttrPair(
1050+
networkInterfaceSecSchemaName, "project_id",
1051+
"stackit_network.network", "project_id",
1052+
),
1053+
resource.TestCheckResourceAttrPair(
1054+
networkInterfaceSecSchemaName, "network_id",
1055+
"stackit_network.network", "network_id",
1056+
),
1057+
resource.TestCheckResourceAttrSet(networkInterfaceSecSchemaName, "network_interface_id"),
1058+
resource.TestCheckResourceAttr(
1059+
networkInterfaceSecSchemaName, "name",
1060+
fmt.Sprintf("%s-%s", fmt.Sprintf("%s-updated", networkInterfaceResource["name"]), nicAttachTfName),
1061+
),
1062+
1063+
// Network Interface Attachment
1064+
resource.TestCheckResourceAttrPair(
1065+
"stackit_server_network_interface_attach.attach_nic", "project_id",
1066+
networkInterfaceSecSchemaName, "project_id",
1067+
),
1068+
resource.TestCheckResourceAttrPair(
1069+
"stackit_server_network_interface_attach.attach_nic", "server_id",
1070+
"stackit_server.server", "server_id",
1071+
),
1072+
resource.TestCheckResourceAttrPair(
1073+
"stackit_server_network_interface_attach.attach_nic", "network_interface_id",
1074+
networkInterfaceSecSchemaName, "network_interface_id",
1075+
),
9531076
),
9541077
},
9551078
// Deletion is done by the framework implicitly
@@ -1107,6 +1230,7 @@ func TestAccPublicIp(t *testing.T) {
11071230
"[%q]",
11081231
networkResource["nameserver0"],
11091232
),
1233+
networkInterfaceResource["tfName"],
11101234
networkInterfaceResource["name"],
11111235
fmt.Sprintf(`
11121236
resource "stackit_public_ip" "public_ip" {
@@ -1146,6 +1270,7 @@ func TestAccPublicIp(t *testing.T) {
11461270
"[%q]",
11471271
networkResource["nameserver0"],
11481272
),
1273+
networkInterfaceResource["tfName"],
11491274
networkInterfaceResource["name"],
11501275
fmt.Sprintf(`
11511276
resource "stackit_public_ip" "public_ip" {
@@ -1198,6 +1323,7 @@ func TestAccPublicIp(t *testing.T) {
11981323
"[%q]",
11991324
networkResource["nameserver0"],
12001325
),
1326+
networkInterfaceResource["tfName"],
12011327
networkInterfaceResource["name"],
12021328
fmt.Sprintf(`
12031329
resource "stackit_public_ip" "public_ip" {

stackit/internal/services/iaas/server/resource.go

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -888,12 +888,39 @@ func mapFields(ctx context.Context, serverResp *iaas.Server, model *Model) error
888888
for _, nic := range *serverResp.Nics {
889889
respNics = append(respNics, *nic.NicId)
890890
}
891-
nicTF, diags := types.ListValueFrom(ctx, types.StringType, respNics)
892-
if diags.HasError() {
893-
return fmt.Errorf("failed to map networkInterfaces: %w", core.DiagsToError(diags))
891+
892+
var modelNics []string
893+
for _, modelNic := range model.NetworkInterfaces.Elements() {
894+
modelNicString, ok := modelNic.(types.String)
895+
if !ok {
896+
return fmt.Errorf("type assertion for network interfaces failed")
897+
}
898+
modelNics = append(modelNics, modelNicString.ValueString())
894899
}
895900

896-
model.NetworkInterfaces = nicTF
901+
var filteredNics []string
902+
for _, modelNic := range modelNics {
903+
for _, nic := range respNics {
904+
if nic == modelNic {
905+
filteredNics = append(filteredNics, nic)
906+
break
907+
}
908+
}
909+
}
910+
911+
// Sorts the filteredNics based on the modelNics order
912+
resultNics := utils.ReconcileStringSlices(modelNics, filteredNics)
913+
914+
if len(resultNics) != 0 {
915+
nicTF, diags := types.ListValueFrom(ctx, types.StringType, resultNics)
916+
if diags.HasError() {
917+
return fmt.Errorf("failed to map networkInterfaces: %w", core.DiagsToError(diags))
918+
}
919+
920+
model.NetworkInterfaces = nicTF
921+
} else {
922+
model.NetworkInterfaces = types.ListNull(types.StringType)
923+
}
897924
} else {
898925
model.NetworkInterfaces = types.ListNull(types.StringType)
899926
}

stackit/internal/services/iaas/server/resource_test.go

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -98,16 +98,13 @@ func TestMapFields(t *testing.T) {
9898
Labels: types.MapValueMust(types.StringType, map[string]attr.Value{
9999
"key": types.StringValue("value"),
100100
}),
101-
ImageId: types.StringValue("image_id"),
102-
NetworkInterfaces: types.ListValueMust(types.StringType, []attr.Value{
103-
types.StringValue("nic1"),
104-
types.StringValue("nic2"),
105-
}),
106-
KeypairName: types.StringValue("keypair_name"),
107-
AffinityGroup: types.StringValue("group_id"),
108-
CreatedAt: types.StringValue(testTimestampValue),
109-
UpdatedAt: types.StringValue(testTimestampValue),
110-
LaunchedAt: types.StringValue(testTimestampValue),
101+
ImageId: types.StringValue("image_id"),
102+
NetworkInterfaces: types.ListNull(types.StringType),
103+
KeypairName: types.StringValue("keypair_name"),
104+
AffinityGroup: types.StringValue("group_id"),
105+
CreatedAt: types.StringValue(testTimestampValue),
106+
UpdatedAt: types.StringValue(testTimestampValue),
107+
LaunchedAt: types.StringValue(testTimestampValue),
111108
},
112109
true,
113110
},

0 commit comments

Comments
 (0)