feat(SKE): support for DNS extension (#492)

* Feat(SKE): support DNS extension

* generate docs

* fix attributes required/optional

* add comment to acceptance test DNS zones

* regenerate docs

* fix typos

* generate docs
This commit is contained in:
Kumm-Kai 2024-08-06 13:39:58 +00:00 committed by GitHub
parent aface95620
commit 93c7afe73e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 198 additions and 18 deletions

View file

@ -32,7 +32,7 @@ data "stackit_mongodbflex_instance" "example" {
- `acl` (List of String) The Access Control List (ACL) for the MongoDB Flex instance.
- `backup_schedule` (String) The backup schedule. Should follow the cron scheduling system format (e.g. "0 0 * * *").
- `flavor` (Attributes) (see [below for nested schema](#nestedatt--flavor))
- `id` (String) Terraform's internal data source. ID. It is structured as "`project_id`,`instance_id`".
- `id` (String) Terraform's internal data source ID. It is structured as "`project_id`,`instance_id`".
- `name` (String) Instance name.
- `options` (Attributes) Custom parameters for the MongoDB Flex instance. (see [below for nested schema](#nestedatt--options))
- `replicas` (Number)

View file

@ -4,7 +4,7 @@ page_title: "stackit_postgresql_credential Data Source - stackit"
subcategory: ""
description: |-
PostgreSQL credential data source schema. Must have a region specified in the provider configuration.
!> The STACKIT PostgreSQL service has reached its end of support on June 30th 2024. Resources of this type have stopped working since then. Use stackit_postgresflex_user instead. For more details, check
!> The STACKIT PostgreSQL service has reached its end of support on June 30th 2024. Resources of this type have stopped working since then. Use stackit_postgresflex_user instead. For more details, check https://docs.stackit.cloud/stackit/en/bring-your-data-to-stackit-postgresql-flex-138347648.html
---
# stackit_postgresql_credential (Data Source)

View file

@ -4,7 +4,7 @@ page_title: "stackit_postgresql_instance Data Source - stackit"
subcategory: ""
description: |-
PostgreSQL instance data source schema. Must have a region specified in the provider configuration.
!> The STACKIT PostgreSQL service has reached its end of support on June 30th 2024. Resources of this type have stopped working since then. Use stackit_postgresflex_instance instead. For more details, check
!> The STACKIT PostgreSQL service has reached its end of support on June 30th 2024. Resources of this type have stopped working since then. Use stackit_postgresflex_instance instead. For more details, check https://docs.stackit.cloud/stackit/en/bring-your-data-to-stackit-postgresql-flex-138347648.html
---
# stackit_postgresql_instance (Data Source)

View file

@ -50,6 +50,7 @@ Read-Only:
- `acl` (Attributes) Cluster access control configuration (see [below for nested schema](#nestedatt--extensions--acl))
- `argus` (Attributes) A single argus block as defined below (see [below for nested schema](#nestedatt--extensions--argus))
- `dns` (Attributes) DNS extension configuration (see [below for nested schema](#nestedatt--extensions--dns))
<a id="nestedatt--extensions--acl"></a>
### Nested Schema for `extensions.acl`
@ -69,6 +70,15 @@ Read-Only:
- `enabled` (Boolean) Flag to enable/disable argus extensions.
<a id="nestedatt--extensions--dns"></a>
### Nested Schema for `extensions.dns`
Read-Only:
- `enabled` (Boolean) Flag to enable/disable DNS extensions
- `zones` (List of String) Specify a list of domain filters for externalDNS (e.g., `foo.runs.onstackit.cloud`)
<a id="nestedatt--hibernations"></a>
### Nested Schema for `hibernations`

View file

@ -4,7 +4,7 @@ page_title: "stackit_postgresql_credential Resource - stackit"
subcategory: ""
description: |-
PostgreSQL credential resource schema. Must have a region specified in the provider configuration.
!> The STACKIT PostgreSQL service has reached its end of support on June 30th 2024. Resources of this type have stopped working since then. Use stackit_postgresflex_user instead. For more details, check
!> The STACKIT PostgreSQL service has reached its end of support on June 30th 2024. Resources of this type have stopped working since then. Use stackit_postgresflex_user instead. For more details, check https://docs.stackit.cloud/stackit/en/bring-your-data-to-stackit-postgresql-flex-138347648.html
---
# stackit_postgresql_credential (Resource)

View file

@ -4,7 +4,7 @@ page_title: "stackit_postgresql_instance Resource - stackit"
subcategory: ""
description: |-
PostgreSQL instance resource schema. Must have a region specified in the provider configuration.
!> The STACKIT PostgreSQL service has reached its end of support on June 30th 2024. Resources of this type have stopped working since then. Use stackit_postgresflex_instance instead. Check on how to backup and restore an instance from PostgreSQL to PostgreSQL Flex, then import the resource to Terraform using an "import" block ()
!> The STACKIT PostgreSQL service has reached its end of support on June 30th 2024. Resources of this type have stopped working since then. Use stackit_postgresflex_instance instead. Check https://docs.stackit.cloud/stackit/en/bring-your-data-to-stackit-postgresql-flex-138347648.html on how to backup and restore an instance from PostgreSQL to PostgreSQL Flex, then import the resource to Terraform using an "import" block (https://developer.hashicorp.com/terraform/language/import)
---
# stackit_postgresql_instance (Resource)

View file

@ -115,17 +115,15 @@ Optional:
- `acl` (Attributes) Cluster access control configuration. (see [below for nested schema](#nestedatt--extensions--acl))
- `argus` (Attributes) A single argus block as defined below. (see [below for nested schema](#nestedatt--extensions--argus))
- `dns` (Attributes) DNS extension configuration (see [below for nested schema](#nestedatt--extensions--dns))
<a id="nestedatt--extensions--acl"></a>
### Nested Schema for `extensions.acl`
Required:
- `enabled` (Boolean) Is ACL enabled?
Optional:
- `allowed_cidrs` (List of String) Specify a list of CIDRs to whitelist.
- `enabled` (Boolean) Is ACL enabled?
<a id="nestedatt--extensions--argus"></a>
@ -133,11 +131,20 @@ Optional:
Required:
- `argus_instance_id` (String) Argus instance ID to choose which Argus instance is used. Required when enabled is set to `true`.
- `enabled` (Boolean) Flag to enable/disable Argus extensions.
<a id="nestedatt--extensions--dns"></a>
### Nested Schema for `extensions.dns`
Required:
- `enabled` (Boolean) Flag to enable/disable DNS extensions
Optional:
- `argus_instance_id` (String) Argus instance ID to choose which Argus instance is used. Required when enabled is set to `true`.
- `zones` (List of String) Specify a list of domain filters for externalDNS (e.g., `foo.runs.onstackit.cloud`)

View file

@ -296,6 +296,21 @@ func (r *clusterDataSource) Schema(_ context.Context, _ datasource.SchemaRequest
},
},
},
"dns": schema.SingleNestedAttribute{
Description: "DNS extension configuration",
Computed: true,
Attributes: map[string]schema.Attribute{
"enabled": schema.BoolAttribute{
Description: "Flag to enable/disable DNS extensions",
Computed: true,
},
"zones": schema.ListAttribute{
Description: "Specify a list of domain filters for externalDNS (e.g., `foo.runs.onstackit.cloud`)",
Computed: true,
ElementType: types.StringType,
},
},
},
},
},
"kube_config": schema.StringAttribute{

View file

@ -178,12 +178,14 @@ var hibernationTypes = map[string]attr.Type{
type extensions struct {
Argus types.Object `tfsdk:"argus"`
ACL types.Object `tfsdk:"acl"`
DNS types.Object `tfsdk:"dns"`
}
// Types corresponding to extensions
var extensionsTypes = map[string]attr.Type{
"argus": basetypes.ObjectType{AttrTypes: argusTypes},
"acl": basetypes.ObjectType{AttrTypes: aclTypes},
"dns": basetypes.ObjectType{AttrTypes: dnsTypes},
}
// Struct corresponding to extensions.ACL
@ -210,6 +212,18 @@ var argusTypes = map[string]attr.Type{
"argus_instance_id": basetypes.StringType{},
}
// Struct corresponding to extensions.DNS
type dns struct {
Enabled types.Bool `tfsdk:"enabled"`
Zones types.List `tfsdk:"zones"`
}
// Types corresponding to DNS
var dnsTypes = map[string]attr.Type{
"enabled": basetypes.BoolType{},
"zones": basetypes.ListType{ElemType: types.StringType},
}
// NewClusterResource is a helper function to simplify the provider implementation.
func NewClusterResource() resource.Resource {
return &clusterResource{}
@ -568,7 +582,7 @@ func (r *clusterResource) Schema(_ context.Context, _ resource.SchemaRequest, re
},
"argus_instance_id": schema.StringAttribute{
Description: "Argus instance ID to choose which Argus instance is used. Required when enabled is set to `true`.",
Optional: true,
Required: true,
},
},
},
@ -582,6 +596,21 @@ func (r *clusterResource) Schema(_ context.Context, _ resource.SchemaRequest, re
},
"allowed_cidrs": schema.ListAttribute{
Description: "Specify a list of CIDRs to whitelist.",
Required: true,
ElementType: types.StringType,
},
},
},
"dns": schema.SingleNestedAttribute{
Description: "DNS extension configuration",
Optional: true,
Attributes: map[string]schema.Attribute{
"enabled": schema.BoolAttribute{
Description: "Flag to enable/disable DNS extensions",
Required: true,
},
"zones": schema.ListAttribute{
Description: "Specify a list of domain filters for externalDNS (e.g., `foo.runs.onstackit.cloud`)",
Optional: true,
ElementType: types.StringType,
},
@ -1175,9 +1204,30 @@ func toExtensionsPayload(ctx context.Context, m *Model) (*ske.Extension, error)
}
}
var skeDNS *ske.DNS
if !(ex.DNS.IsNull() || ex.DNS.IsUnknown()) {
dns := dns{}
diags = ex.DNS.As(ctx, &dns, basetypes.ObjectAsOptions{})
if diags.HasError() {
return nil, fmt.Errorf("converting extensions.dns object: %v", diags.Errors())
}
dnsEnabled := conversion.BoolValueToPointer(dns.Enabled)
zones := []string{}
diags = dns.Zones.ElementsAs(ctx, &zones, true)
if diags.HasError() {
return nil, fmt.Errorf("converting extensions.dns.zones object: %v", diags.Errors())
}
skeDNS = &ske.DNS{
Enabled: dnsEnabled,
Zones: &zones,
}
}
return &ske.Extension{
Acl: skeAcl,
Argus: skeArgus,
Dns: skeDNS,
}, nil
}
@ -1584,7 +1634,7 @@ func getMaintenanceTimes(ctx context.Context, cl *ske.Cluster, m *Model) (startT
return startTime, endTime, nil
}
func checkDisabledExtensions(ctx context.Context, ex extensions) (aclDisabled, argusDisabled bool, err error) {
func checkDisabledExtensions(ctx context.Context, ex extensions) (aclDisabled, argusDisabled, dnsDisabled bool, err error) {
var diags diag.Diagnostics
acl := acl{}
if ex.ACL.IsNull() {
@ -1592,7 +1642,7 @@ func checkDisabledExtensions(ctx context.Context, ex extensions) (aclDisabled, a
} else {
diags = ex.ACL.As(ctx, &acl, basetypes.ObjectAsOptions{})
if diags.HasError() {
return false, false, fmt.Errorf("converting extensions.acl object: %v", diags.Errors())
return false, false, false, fmt.Errorf("converting extensions.acl object: %v", diags.Errors())
}
}
@ -1602,11 +1652,21 @@ func checkDisabledExtensions(ctx context.Context, ex extensions) (aclDisabled, a
} else {
diags = ex.Argus.As(ctx, &argus, basetypes.ObjectAsOptions{})
if diags.HasError() {
return false, false, fmt.Errorf("converting extensions.argus object: %v", diags.Errors())
return false, false, false, fmt.Errorf("converting extensions.argus object: %v", diags.Errors())
}
}
return !acl.Enabled.ValueBool(), !argus.Enabled.ValueBool(), nil
dns := dns{}
if ex.DNS.IsNull() {
dns.Enabled = types.BoolValue(false)
} else {
diags = ex.DNS.As(ctx, &dns, basetypes.ObjectAsOptions{})
if diags.HasError() {
return false, false, false, fmt.Errorf("converting extensions.dns object: %v", diags.Errors())
}
}
return !acl.Enabled.ValueBool(), !argus.Enabled.ValueBool(), !dns.Enabled.ValueBool(), nil
}
func mapExtensions(ctx context.Context, cl *ske.Cluster, m *Model) error {
@ -1633,12 +1693,12 @@ func mapExtensions(ctx context.Context, cl *ske.Cluster, m *Model) error {
// If we parse that object into the terraform model, it will produce an inconsistent result after apply
// error
aclDisabled, argusDisabled, err := checkDisabledExtensions(ctx, ex)
aclDisabled, argusDisabled, dnsDisabled, err := checkDisabledExtensions(ctx, ex)
if err != nil {
return fmt.Errorf("checking if extensions are disabled: %w", err)
}
disabledExtensions := false
if aclDisabled && argusDisabled {
if aclDisabled && argusDisabled && dnsDisabled {
disabledExtensions = true
}
@ -1700,9 +1760,35 @@ func mapExtensions(ctx context.Context, cl *ske.Cluster, m *Model) error {
argusExtension = ex.Argus
}
dnsExtension := types.ObjectNull(dnsTypes)
if cl.Extensions.Dns != nil {
enabled := types.BoolNull()
if cl.Extensions.Dns.Enabled != nil {
enabled = types.BoolValue(*cl.Extensions.Dns.Enabled)
}
zonesList, diags := types.ListValueFrom(ctx, types.StringType, cl.Extensions.Dns.Zones)
if diags.HasError() {
return fmt.Errorf("creating zones list: %w", core.DiagsToError(diags))
}
dnsValues := map[string]attr.Value{
"enabled": enabled,
"zones": zonesList,
}
dnsExtension, diags = types.ObjectValue(dnsTypes, dnsValues)
if diags.HasError() {
return fmt.Errorf("creating dns: %w", core.DiagsToError(diags))
}
} else if dnsDisabled && !ex.DNS.IsNull() {
dnsExtension = ex.DNS
}
extensionsValues := map[string]attr.Value{
"acl": aclExtension,
"argus": argusExtension,
"dns": dnsExtension,
}
extensions, diags := types.ObjectValue(extensionsTypes, extensionsValues)

View file

@ -72,6 +72,10 @@ func TestMapFields(t *testing.T) {
ArgusInstanceId: utils.Ptr("aid"),
Enabled: utils.Ptr(true),
},
Dns: &ske.DNS{
Zones: &[]string{"foo.onstackit.cloud"},
Enabled: utils.Ptr(true),
},
},
Hibernation: &ske.Hibernation{
Schedules: &[]ske.HibernationSchedule{
@ -228,6 +232,12 @@ func TestMapFields(t *testing.T) {
"enabled": types.BoolValue(true),
"argus_instance_id": types.StringValue("aid"),
}),
"dns": types.ObjectValueMust(dnsTypes, map[string]attr.Value{
"enabled": types.BoolValue(true),
"zones": types.ListValueMust(types.StringType, []attr.Value{
types.StringValue("foo.onstackit.cloud"),
}),
}),
}),
KubeConfig: types.StringNull(),
},
@ -270,6 +280,10 @@ func TestMapFields(t *testing.T) {
ArgusInstanceId: nil,
Enabled: utils.Ptr(true),
},
Dns: &ske.DNS{
Zones: nil,
Enabled: utils.Ptr(true),
},
},
Name: utils.Ptr("name"),
},
@ -291,6 +305,10 @@ func TestMapFields(t *testing.T) {
"enabled": types.BoolValue(true),
"argus_instance_id": types.StringNull(),
}),
"dns": types.ObjectValueMust(dnsTypes, map[string]attr.Value{
"enabled": types.BoolValue(true),
"zones": types.ListNull(types.StringType),
}),
}),
KubeConfig: types.StringNull(),
},
@ -307,6 +325,10 @@ func TestMapFields(t *testing.T) {
"enabled": types.BoolValue(false),
"argus_instance_id": types.StringNull(),
}),
"dns": types.ObjectValueMust(dnsTypes, map[string]attr.Value{
"enabled": types.BoolValue(false),
"zones": types.ListNull(types.StringType),
}),
}),
types.ListNull(types.ObjectType{AttrTypes: nodePoolTypes}),
&ske.Cluster{
@ -331,6 +353,10 @@ func TestMapFields(t *testing.T) {
"enabled": types.BoolValue(false),
"argus_instance_id": types.StringNull(),
}),
"dns": types.ObjectValueMust(dnsTypes, map[string]attr.Value{
"enabled": types.BoolValue(false),
"zones": types.ListNull(types.StringType),
}),
}),
KubeConfig: types.StringNull(),
},
@ -349,6 +375,10 @@ func TestMapFields(t *testing.T) {
"enabled": types.BoolValue(false),
"argus_instance_id": types.StringValue("id"),
}),
"dns": types.ObjectValueMust(dnsTypes, map[string]attr.Value{
"enabled": types.BoolValue(true),
"zones": types.ListNull(types.StringType),
}),
}),
types.ListNull(types.ObjectType{AttrTypes: nodePoolTypes}),
&ske.Cluster{
@ -357,6 +387,10 @@ func TestMapFields(t *testing.T) {
AllowedCidrs: &[]string{"cidr1"},
Enabled: utils.Ptr(true),
},
Dns: &ske.DNS{
Zones: nil,
Enabled: utils.Ptr(true),
},
},
Name: utils.Ptr("name"),
},
@ -380,6 +414,10 @@ func TestMapFields(t *testing.T) {
"enabled": types.BoolValue(false),
"argus_instance_id": types.StringValue("id"),
}),
"dns": types.ObjectValueMust(dnsTypes, map[string]attr.Value{
"enabled": types.BoolValue(true),
"zones": types.ListNull(types.StringType),
}),
}),
KubeConfig: types.StringNull(),
},
@ -457,6 +495,10 @@ func TestMapFields(t *testing.T) {
ArgusInstanceId: utils.Ptr("aid"),
Enabled: utils.Ptr(true),
},
Dns: &ske.DNS{
Zones: &[]string{"zone1"},
Enabled: utils.Ptr(true),
},
},
Hibernation: &ske.Hibernation{
Schedules: &[]ske.HibernationSchedule{
@ -594,6 +636,12 @@ func TestMapFields(t *testing.T) {
"enabled": types.BoolValue(true),
"argus_instance_id": types.StringValue("aid"),
}),
"dns": types.ObjectValueMust(dnsTypes, map[string]attr.Value{
"enabled": types.BoolValue(true),
"zones": types.ListValueMust(types.StringType, []attr.Value{
types.StringValue("zone1"),
}),
}),
}),
KubeConfig: types.StringNull(),
},

View file

@ -50,6 +50,8 @@ var clusterResource = map[string]string{
"extensions_acl_cidrs": "192.168.0.0/24",
"extensions_argus_enabled": "false",
"extensions_argus_instance_id": "aaaaaaaa-1111-2222-3333-444444444444", // A not-existing Argus ID let the creation time-out.
"extensions_dns_enabled": "true",
"extensions_dns_zones": "foo.onstackit.cloud", // Dummy DNS zone, replace when running the tests!
"hibernations_start": "0 16 * * *",
"hibernations_end": "0 18 * * *",
"hibernations_timezone": "Europe/Berlin",
@ -104,6 +106,10 @@ func getConfig(kubernetesVersion, nodePoolMachineOSVersion string, maintenanceEn
enabled = %s
argus_instance_id = "%s"
}
dns = {
enabled = %s
zones = ["%s"]
}
}
hibernations = [{
start = "%s"
@ -167,6 +173,8 @@ func getConfig(kubernetesVersion, nodePoolMachineOSVersion string, maintenanceEn
clusterResource["extensions_acl_cidrs"],
clusterResource["extensions_argus_enabled"],
clusterResource["extensions_argus_instance_id"],
clusterResource["extensions_dns_enabled"],
clusterResource["extensions_dns_zones"],
clusterResource["hibernations_start"],
clusterResource["hibernations_end"],
clusterResource["hibernations_timezone"],
@ -231,6 +239,9 @@ func TestAccSKE(t *testing.T) {
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "extensions.acl.allowed_cidrs.0", clusterResource["extensions_acl_cidrs"]),
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "extensions.argus.enabled", clusterResource["extensions_argus_enabled"]),
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "extensions.argus.argus_instance_id", clusterResource["extensions_argus_instance_id"]),
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "extensions.dns.enabled", clusterResource["extensions_dns_enabled"]),
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "extensions.dns.zones.#", "1"),
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "extensions.dns.zones.0", clusterResource["extensions_dns_zones"]),
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "hibernations.#", "1"),
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "hibernations.0.start", clusterResource["hibernations_start"]),
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "hibernations.0.end", clusterResource["hibernations_end"]),
@ -396,7 +407,7 @@ func TestAccSKE(t *testing.T) {
ImportState: true,
ImportStateVerify: true,
// The fields are not provided in the SKE API when disabled, although set actively.
ImportStateVerifyIgnore: []string{"kubernetes_version_min", "kube_config", "node_pools.0.os_version_min", "extensions.argus.%", "extensions.argus.argus_instance_id", "extensions.argus.enabled", "extensions.acl.enabled", "extensions.acl.allowed_cidrs", "extensions.acl.allowed_cidrs.#", "extensions.acl.%"},
ImportStateVerifyIgnore: []string{"kubernetes_version_min", "kube_config", "node_pools.0.os_version_min", "extensions.argus.%", "extensions.argus.argus_instance_id", "extensions.argus.enabled", "extensions.acl.enabled", "extensions.acl.allowed_cidrs", "extensions.acl.allowed_cidrs.#", "extensions.acl.%", "extensions.dns.enabled", "extensions.dns.zones", "extensions.dns.zones.#", "extensions.dns.zones.%"},
},
// 4) Import minimal cluster
{
@ -453,6 +464,9 @@ func TestAccSKE(t *testing.T) {
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "extensions.acl.allowed_cidrs.0", clusterResource["extensions_acl_cidrs"]),
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "extensions.argus.enabled", clusterResource["extensions_argus_enabled"]),
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "extensions.argus.argus_instance_id", clusterResource["extensions_argus_instance_id"]),
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "extensions.dns.enabled", clusterResource["extensions_dns_enabled"]),
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "extensions.dns.zones.#", "1"),
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "extensions.dns.zones.0", clusterResource["extensions_dns_zones"]),
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "hibernations.#", "1"),
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "hibernations.0.start", clusterResource["hibernations_start"]),
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "hibernations.0.end", clusterResource["hibernations_end"]),