Skip to content

Commit f2bad2b

Browse files
authored
feat(instance): add support for admin_password_encryption_ssh_key_id (#3172)
* feat(instance): add support for admin_password_encryption_ssh_key_id * add validation * markdown-lint
1 parent 5067452 commit f2bad2b

File tree

5 files changed

+4290
-0
lines changed

5 files changed

+4290
-0
lines changed

docs/resources/instance_server.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,10 @@ attached to the server. Updates to this field will trigger a stop/start of the s
260260

261261
- `protected` - (Optional) Set to true to activate server protection option.
262262

263+
- `admin_password_encryption_ssh_key_id` - (Optional) The ID of the SSH RSA key that will be used to encrypt the initial admin password for OS requiring it.
264+
Mandatory for Windows OS. The public_key value of this key is used to encrypt the admin password.
265+
When set to an empty string, it resets this value and admin_password_encrypted_value to an empty string so a new password may be generated.
266+
263267
- `zone` - (Defaults to [provider](../index.md#zone) `zone`) The [zone](../guides/regions_and_zones.md#zones) in which the server should be created.
264268

265269
- `project_id` - (Defaults to [provider](../index.md#project_id) `project_id`) The ID of the project the server is associated with.

internal/services/instance/server.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,12 @@ func ResourceServer() *schema.Resource {
374374
},
375375
},
376376
},
377+
"admin_password_encryption_ssh_key_id": {
378+
Type: schema.TypeString,
379+
Optional: true,
380+
ValidateDiagFunc: verify.IsUUIDOrEmpty(),
381+
Description: "The ID of the IAM SSH key used to encrypt the initial admin password on a Windows server",
382+
},
377383
"zone": zonal.Schema(),
378384
"organization_id": account.OrganizationIDSchema(),
379385
"project_id": account.ProjectIDSchema(),
@@ -439,6 +445,10 @@ func ResourceInstanceServerCreate(ctx context.Context, d *schema.ResourceData, m
439445
req.PlacementGroup = types.ExpandStringPtr(zonal.ExpandID(placementGroupID).ID)
440446
}
441447

448+
if adminPasswordEncryptionSSHKeyID, ok := d.GetOk("admin_password_encryption_key_ssh_id"); ok {
449+
req.AdminPasswordEncryptionSSHKeyID = types.ExpandStringPtr(adminPasswordEncryptionSSHKeyID)
450+
}
451+
442452
serverType := getServerType(ctx, api.API, req.Zone, req.CommercialType)
443453
if serverType == nil {
444454
return diag.Diagnostics{{
@@ -715,6 +725,10 @@ func ResourceInstanceServerRead(ctx context.Context, d *schema.ResourceData, m a
715725
_ = d.Set("ipv6_prefix_length", nil)
716726
}
717727

728+
if server.AdminPasswordEncryptionSSHKeyID != nil {
729+
_ = d.Set("admin_password_encryption_ssh_key_id", server.AdminPasswordEncryptionSSHKeyID)
730+
}
731+
718732
var additionalVolumesIDs []string
719733

720734
for i, serverVolume := range sortVolumeServer(server.Volumes) {
@@ -973,6 +987,10 @@ func ResourceInstanceServerUpdate(ctx context.Context, d *schema.ResourceData, m
973987
}
974988
}
975989

990+
if d.HasChange("admin_password_encryption_ssh_key_id") {
991+
updateRequest.AdminPasswordEncryptionSSHKeyID = types.ExpandUpdatedStringPtr(d.Get("admin_password_encryption_ssh_key_id").(string))
992+
}
993+
976994
////
977995
// Update reserved IP
978996
////

internal/services/instance/server_test.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/scaleway/terraform-provider-scaleway/v2/internal/locality"
1515
"github.com/scaleway/terraform-provider-scaleway/v2/internal/locality/zonal"
1616
"github.com/scaleway/terraform-provider-scaleway/v2/internal/meta"
17+
iamchecks "github.com/scaleway/terraform-provider-scaleway/v2/internal/services/iam/testfuncs"
1718
"github.com/scaleway/terraform-provider-scaleway/v2/internal/services/instance"
1819
instancechecks "github.com/scaleway/terraform-provider-scaleway/v2/internal/services/instance/testfuncs"
1920
"github.com/stretchr/testify/assert"
@@ -2097,6 +2098,78 @@ func TestAccServer_PrivateNetworkMissingPNIC(t *testing.T) {
20972098
})
20982099
}
20992100

2101+
func TestAccServer_AdminPasswordEncryptionSSHKeyID(t *testing.T) {
2102+
tt := acctest.NewTestTools(t)
2103+
defer tt.Cleanup()
2104+
2105+
sshKey := "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEEYrzDOZmhItdKaDAEqJQ4ORS2GyBMtBozYsK5kiXXX [email protected]"
2106+
2107+
resource.ParallelTest(t, resource.TestCase{
2108+
PreCheck: func() { acctest.PreCheck(t) },
2109+
ProviderFactories: tt.ProviderFactories,
2110+
CheckDestroy: resource.ComposeTestCheckFunc(
2111+
instancechecks.IsServerDestroyed(tt),
2112+
iamchecks.CheckSSHKeyDestroy(tt),
2113+
),
2114+
Steps: []resource.TestStep{
2115+
{
2116+
Config: fmt.Sprintf(`
2117+
resource "scaleway_iam_ssh_key" "main" {
2118+
name = "test-acc-admin-pwd-encryption"
2119+
public_key = %q
2120+
}
2121+
2122+
resource "scaleway_instance_server" "main" {
2123+
type = "POP2-2C-8G-WIN"
2124+
image = "windows_server_2022"
2125+
admin_password_encryption_ssh_key_id = scaleway_iam_ssh_key.main.id
2126+
}
2127+
`, sshKey),
2128+
Check: resource.ComposeTestCheckFunc(
2129+
iamchecks.CheckSSHKeyExists(tt, "scaleway_iam_ssh_key.main"),
2130+
resource.TestCheckResourceAttr("scaleway_instance_server.main", "type", "POP2-2C-8G-WIN"),
2131+
resource.TestCheckResourceAttr("scaleway_instance_server.main", "image", "windows_server_2022"),
2132+
resource.TestCheckResourceAttrPair("scaleway_instance_server.main", "admin_password_encryption_ssh_key_id", "scaleway_iam_ssh_key.main", "id"),
2133+
),
2134+
},
2135+
{
2136+
Config: fmt.Sprintf(`
2137+
resource "scaleway_iam_ssh_key" "main" {
2138+
name = "test-acc-admin-pwd-encryption"
2139+
public_key = %q
2140+
}
2141+
2142+
resource "scaleway_instance_server" "main" {
2143+
type = "POP2-2C-8G-WIN"
2144+
image = "windows_server_2022"
2145+
admin_password_encryption_ssh_key_id = ""
2146+
}
2147+
`, sshKey),
2148+
Check: resource.ComposeTestCheckFunc(
2149+
resource.TestCheckResourceAttr("scaleway_instance_server.main", "admin_password_encryption_ssh_key_id", ""),
2150+
),
2151+
},
2152+
{
2153+
Config: fmt.Sprintf(`
2154+
resource "scaleway_iam_ssh_key" "main" {
2155+
name = "test-acc-admin-pwd-encryption"
2156+
public_key = %q
2157+
}
2158+
2159+
resource "scaleway_instance_server" "main" {
2160+
type = "POP2-2C-8G-WIN"
2161+
image = "windows_server_2022"
2162+
admin_password_encryption_ssh_key_id = scaleway_iam_ssh_key.main.id
2163+
}
2164+
`, sshKey),
2165+
Check: resource.ComposeTestCheckFunc(
2166+
resource.TestCheckResourceAttrPair("scaleway_instance_server.main", "admin_password_encryption_ssh_key_id", "scaleway_iam_ssh_key.main", "id"),
2167+
),
2168+
},
2169+
},
2170+
})
2171+
}
2172+
21002173
func TestGetEndOfServiceDate(t *testing.T) {
21012174
tt := acctest.NewTestTools(t)
21022175
client := meta.ExtractScwClient(tt.Meta)

internal/services/instance/testdata/server-admin-password-encryption-ssh-key-id.cassette.yaml

Lines changed: 4167 additions & 0 deletions
Large diffs are not rendered by default.

internal/verify/uuid.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,34 @@ func IsUUID() schema.SchemaValidateDiagFunc {
4242
}
4343
}
4444

45+
func IsUUIDOrEmpty() schema.SchemaValidateDiagFunc {
46+
return func(value any, path cty.Path) diag.Diagnostics {
47+
uuid, isString := value.(string)
48+
if !isString {
49+
return diag.Diagnostics{diag.Diagnostic{
50+
Severity: diag.Error,
51+
Summary: "invalid UUID not a string",
52+
AttributePath: path,
53+
}}
54+
}
55+
56+
if uuid == "" {
57+
return nil
58+
}
59+
60+
if !validation.IsUUID(uuid) {
61+
return diag.Diagnostics{diag.Diagnostic{
62+
Severity: diag.Error,
63+
Summary: "invalid UUID: " + uuid,
64+
AttributePath: path,
65+
Detail: "format should be 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' (36) and contains valid hexadecimal characters",
66+
}}
67+
}
68+
69+
return nil
70+
}
71+
}
72+
4573
func IsUUIDWithLocality() schema.SchemaValidateDiagFunc {
4674
return func(value any, path cty.Path) diag.Diagnostics {
4775
uuid, isString := value.(string)

0 commit comments

Comments
 (0)