Skip to content

Commit fa5f98c

Browse files
authoredApr 5, 2024··
fix(server): cannot update placement group (#902)
The `placement_group` field name must be `placement_group_id`, the placement group could not be updated while using the wrong field name. When no placement group is set, we find an id of `0`, which *seem* to be expected by Terraform.
1 parent f57f303 commit fa5f98c

File tree

2 files changed

+73
-4
lines changed

2 files changed

+73
-4
lines changed
 

‎internal/server/resource.go

+12-2
Original file line numberDiff line numberDiff line change
@@ -659,8 +659,8 @@ func resourceServerUpdate(ctx context.Context, d *schema.ResourceData, m interfa
659659
}
660660
}
661661

662-
if d.HasChange("placement_group") {
663-
placementGroupID := d.Get("placement_group").(int)
662+
if d.HasChange("placement_group_id") {
663+
placementGroupID := d.Get("placement_group_id").(int)
664664
if err := setPlacementGroup(ctx, c, server, placementGroupID); err != nil {
665665
return hcloudutil.ErrorToDiag(err)
666666
}
@@ -1212,6 +1212,8 @@ func getServerAttributes(d *schema.ResourceData, s *hcloud.Server) map[string]in
12121212

12131213
if s.PlacementGroup != nil {
12141214
res["placement_group_id"] = s.PlacementGroup.ID
1215+
} else {
1216+
res["placement_group_id"] = nil
12151217
}
12161218

12171219
return res
@@ -1249,6 +1251,14 @@ func getPlacementGroup(ctx context.Context, c *hcloud.Client, id int) (*hcloud.P
12491251

12501252
func setPlacementGroup(ctx context.Context, c *hcloud.Client, server *hcloud.Server, id int) error {
12511253
if server.PlacementGroup != nil {
1254+
if server.Status != hcloud.ServerStatusOff {
1255+
// Removing PG requires the server to be shut down before, this is an invasive operation. We do not currently
1256+
// warn the user about this, so we prefer to forbid the operation until we have a proper framework for
1257+
// shutting down + warning in place.
1258+
return fmt.Errorf("removing a running server from a placement group is currently not supported in the provider. " +
1259+
"You can shutdown the server yourself, apply the changes again and then start the server manually as a workaround")
1260+
}
1261+
12521262
action, _, err := c.Server.RemoveFromPlacementGroup(ctx, server)
12531263
if err != nil {
12541264
return err

‎internal/server/resource_test.go

+61-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package server_test
22

33
import (
4+
"context"
45
"crypto/sha1"
56
"encoding/base64"
67
"fmt"
@@ -22,6 +23,7 @@ import (
2223
"github.com/hetznercloud/terraform-provider-hcloud/internal/teste2e"
2324
"github.com/hetznercloud/terraform-provider-hcloud/internal/testsupport"
2425
"github.com/hetznercloud/terraform-provider-hcloud/internal/testtemplate"
26+
"github.com/hetznercloud/terraform-provider-hcloud/internal/util/hcloudutil"
2527
)
2628

2729
func TestServerResource_Basic(t *testing.T) {
@@ -898,6 +900,13 @@ func TestServerResource_PlacementGroup(t *testing.T) {
898900
}
899901
srvRes.SetRName("server-placement-group")
900902

903+
srvResNoPG := &server.RData{
904+
Name: srvRes.Name,
905+
Type: srvRes.Type,
906+
Image: srvRes.Image,
907+
}
908+
srvResNoPG.SetRName("server-placement-group")
909+
901910
tmplMan := testtemplate.Manager{}
902911

903912
resource.ParallelTest(t, resource.TestCase{
@@ -915,15 +924,65 @@ func TestServerResource_PlacementGroup(t *testing.T) {
915924
Check: resource.ComposeTestCheckFunc(
916925
testsupport.CheckResourceExists(srvRes.TFID(), server.ByID(t, &srv)),
917926
testsupport.CheckResourceExists(pgRes.TFID(), placementgroup.ByID(t, &pg)),
918-
resource.TestCheckResourceAttr(srvRes.TFID(), "name",
919-
fmt.Sprintf("server-placement-group--%d", tmplMan.RandInt)),
927+
resource.TestCheckResourceAttr(srvRes.TFID(), "name", fmt.Sprintf("server-placement-group--%d", tmplMan.RandInt)),
920928
resource.TestCheckResourceAttr(srvRes.TFID(), "server_type", srvRes.Type),
921929
resource.TestCheckResourceAttr(srvRes.TFID(), "image", srvRes.Image),
922930
testsupport.CheckResourceAttrFunc(srvRes.TFID(), "placement_group_id", func() string {
923931
return strconv.Itoa(pg.ID)
924932
}),
925933
),
926934
},
935+
{
936+
// Try to remove PG of running server -> error
937+
Config: tmplMan.Render(t,
938+
"testdata/r/hcloud_placement_group", pgRes,
939+
"testdata/r/hcloud_server", srvResNoPG,
940+
),
941+
ExpectError: regexp.MustCompile("removing a running server from a placement group is currently not supported in the provider.*"),
942+
},
943+
{
944+
// Remove Placement Group
945+
PreConfig: func() {
946+
ctx := context.TODO()
947+
// Removing PG is not support only in TF, we need to shut down the server manually beforehand
948+
client, err := testsupport.CreateClient()
949+
if err != nil {
950+
t.Errorf("PreConfig: failed to create client: %v", err)
951+
return
952+
}
953+
action, _, err := client.Server.Poweroff(ctx, &srv)
954+
if err != nil {
955+
t.Errorf("PreConfig: failed to power off server: %v", err)
956+
return
957+
}
958+
err = hcloudutil.WaitForAction(ctx, &client.Action, action)
959+
if err != nil {
960+
t.Errorf("PreConfig: power off server action failed: %v", err)
961+
return
962+
}
963+
},
964+
Config: tmplMan.Render(t,
965+
"testdata/r/hcloud_placement_group", pgRes,
966+
"testdata/r/hcloud_server", srvResNoPG,
967+
),
968+
Check: resource.ComposeTestCheckFunc(
969+
resource.TestCheckResourceAttr(srvResNoPG.TFID(), "status", "off"),
970+
resource.TestCheckResourceAttr(srvResNoPG.TFID(), "placement_group_id", "0"),
971+
),
972+
},
973+
{
974+
// Add Placement Group back
975+
Config: tmplMan.Render(t,
976+
"testdata/r/hcloud_placement_group", pgRes,
977+
"testdata/r/hcloud_server", srvRes,
978+
),
979+
Check: resource.ComposeTestCheckFunc(
980+
resource.TestCheckResourceAttr(srvResNoPG.TFID(), "status", "running"),
981+
testsupport.CheckResourceAttrFunc(srvRes.TFID(), "placement_group_id", func() string {
982+
return strconv.Itoa(pg.ID)
983+
}),
984+
),
985+
},
927986
},
928987
})
929988
}

0 commit comments

Comments
 (0)
Please sign in to comment.