Allow deleting root volume when deleting server (#651)
Introduce delete_on_termination field. Signed-off-by: Alexander Dahmen <alexander.dahmen@inovex.de>
This commit is contained in:
parent
11875602b8
commit
b6f3c70f15
5 changed files with 100 additions and 14 deletions
|
|
@ -45,6 +45,7 @@ Server datasource schema. Must have a `region` specified in the provider configu
|
||||||
|
|
||||||
Read-Only:
|
Read-Only:
|
||||||
|
|
||||||
|
- `delete_on_termination` (Boolean) Delete the volume during the termination of the server.
|
||||||
- `id` (String) The ID of the source, either image ID or volume ID
|
- `id` (String) The ID of the source, either image ID or volume ID
|
||||||
- `performance_class` (String) The performance class of the server.
|
- `performance_class` (String) The performance class of the server.
|
||||||
- `size` (Number) The size of the boot volume in GB.
|
- `size` (Number) The size of the boot volume in GB.
|
||||||
|
|
|
||||||
|
|
@ -384,7 +384,7 @@ resource "stackit_server" "user-data-from-file" {
|
||||||
- `affinity_group` (String) The affinity group the server is assigned to.
|
- `affinity_group` (String) The affinity group the server is assigned to.
|
||||||
- `availability_zone` (String) The availability zone of the server.
|
- `availability_zone` (String) The availability zone of the server.
|
||||||
- `boot_volume` (Attributes) The boot volume for the server (see [below for nested schema](#nestedatt--boot_volume))
|
- `boot_volume` (Attributes) The boot volume for the server (see [below for nested schema](#nestedatt--boot_volume))
|
||||||
- `desired_status` (String) The desired status of the server resource. Defaults to 'active' Supported values are: `active`, `inactive`, `deallocated`.
|
- `desired_status` (String) The desired status of the server resource. Supported values are: `active`, `inactive`, `deallocated`.
|
||||||
- `image_id` (String) The image ID to be used for an ephemeral disk on the server.
|
- `image_id` (String) The image ID to be used for an ephemeral disk on the server.
|
||||||
- `keypair_name` (String) The name of the keypair used during server creation.
|
- `keypair_name` (String) The name of the keypair used during server creation.
|
||||||
- `labels` (Map of String) Labels are key-value string pairs which can be attached to a resource container
|
- `labels` (Map of String) Labels are key-value string pairs which can be attached to a resource container
|
||||||
|
|
@ -409,5 +409,6 @@ Required:
|
||||||
|
|
||||||
Optional:
|
Optional:
|
||||||
|
|
||||||
|
- `delete_on_termination` (Boolean) Delete the volume during the termination of the server. Only allowed when `source_type` is `image`.
|
||||||
- `performance_class` (String) The performance class of the server.
|
- `performance_class` (String) The performance class of the server.
|
||||||
- `size` (Number) The size of the boot volume in GB. Must be provided when `source_type` is `image`.
|
- `size` (Number) The size of the boot volume in GB. Must be provided when `source_type` is `image`.
|
||||||
|
|
|
||||||
|
|
@ -168,6 +168,10 @@ func (r *serverDataSource) Schema(_ context.Context, _ datasource.SchemaRequest,
|
||||||
Description: "The ID of the source, either image ID or volume ID",
|
Description: "The ID of the source, either image ID or volume ID",
|
||||||
Computed: true,
|
Computed: true,
|
||||||
},
|
},
|
||||||
|
"delete_on_termination": schema.BoolAttribute{
|
||||||
|
Description: "Delete the volume during the termination of the server.",
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"image_id": schema.StringAttribute{
|
"image_id": schema.StringAttribute{
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import (
|
||||||
"github.com/hashicorp/terraform-plugin-framework/path"
|
"github.com/hashicorp/terraform-plugin-framework/path"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/resource"
|
"github.com/hashicorp/terraform-plugin-framework/resource"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
|
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier"
|
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier"
|
"github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/objectplanmodifier"
|
"github.com/hashicorp/terraform-plugin-framework/resource/schema/objectplanmodifier"
|
||||||
|
|
@ -80,18 +81,20 @@ type Model struct {
|
||||||
|
|
||||||
// Struct corresponding to Model.BootVolume
|
// Struct corresponding to Model.BootVolume
|
||||||
type bootVolumeModel struct {
|
type bootVolumeModel struct {
|
||||||
PerformanceClass types.String `tfsdk:"performance_class"`
|
PerformanceClass types.String `tfsdk:"performance_class"`
|
||||||
Size types.Int64 `tfsdk:"size"`
|
Size types.Int64 `tfsdk:"size"`
|
||||||
SourceType types.String `tfsdk:"source_type"`
|
SourceType types.String `tfsdk:"source_type"`
|
||||||
SourceId types.String `tfsdk:"source_id"`
|
SourceId types.String `tfsdk:"source_id"`
|
||||||
|
DeleteOnTermination types.Bool `tfsdk:"delete_on_termination"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Types corresponding to bootVolumeModel
|
// Types corresponding to bootVolumeModel
|
||||||
var bootVolumeTypes = map[string]attr.Type{
|
var bootVolumeTypes = map[string]attr.Type{
|
||||||
"performance_class": basetypes.StringType{},
|
"performance_class": basetypes.StringType{},
|
||||||
"size": basetypes.Int64Type{},
|
"size": basetypes.Int64Type{},
|
||||||
"source_type": basetypes.StringType{},
|
"source_type": basetypes.StringType{},
|
||||||
"source_id": basetypes.StringType{},
|
"source_id": basetypes.StringType{},
|
||||||
|
"delete_on_termination": basetypes.BoolType{},
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewServerResource is a helper function to simplify the provider implementation.
|
// NewServerResource is a helper function to simplify the provider implementation.
|
||||||
|
|
@ -109,6 +112,29 @@ func (r *serverResource) Metadata(_ context.Context, req resource.MetadataReques
|
||||||
resp.TypeName = req.ProviderTypeName + "_server"
|
resp.TypeName = req.ProviderTypeName + "_server"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r serverResource) ValidateConfig(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) {
|
||||||
|
var model Model
|
||||||
|
resp.Diagnostics.Append(req.Config.Get(ctx, &model)...)
|
||||||
|
if resp.Diagnostics.HasError() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert boot volume model
|
||||||
|
var bootVolume = &bootVolumeModel{}
|
||||||
|
if !(model.BootVolume.IsNull() || model.BootVolume.IsUnknown()) {
|
||||||
|
diags := model.BootVolume.As(ctx, bootVolume, basetypes.ObjectAsOptions{})
|
||||||
|
if diags.HasError() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bootVolume.DeleteOnTermination.IsUnknown() && !bootVolume.DeleteOnTermination.IsNull() && !bootVolume.SourceType.IsUnknown() && !bootVolume.SourceType.IsNull() {
|
||||||
|
if bootVolume.SourceType != types.StringValue("image") {
|
||||||
|
core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring server", "You can only provide `delete_on_termination` for `source_type` `image`.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ConfigValidators validates the resource configuration
|
// ConfigValidators validates the resource configuration
|
||||||
func (r *serverResource) ConfigValidators(_ context.Context) []resource.ConfigValidator {
|
func (r *serverResource) ConfigValidators(_ context.Context) []resource.ConfigValidator {
|
||||||
return []resource.ConfigValidator{
|
return []resource.ConfigValidator{
|
||||||
|
|
@ -276,6 +302,13 @@ func (r *serverResource) Schema(_ context.Context, _ resource.SchemaRequest, res
|
||||||
stringplanmodifier.RequiresReplace(),
|
stringplanmodifier.RequiresReplace(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"delete_on_termination": schema.BoolAttribute{
|
||||||
|
Description: "Delete the volume during the termination of the server. Only allowed when `source_type` is `image`.",
|
||||||
|
Optional: true,
|
||||||
|
PlanModifiers: []planmodifier.Bool{
|
||||||
|
boolplanmodifier.RequiresReplace(),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"image_id": schema.StringAttribute{
|
"image_id": schema.StringAttribute{
|
||||||
|
|
@ -359,7 +392,7 @@ func (r *serverResource) Schema(_ context.Context, _ resource.SchemaRequest, res
|
||||||
Computed: true,
|
Computed: true,
|
||||||
},
|
},
|
||||||
"desired_status": schema.StringAttribute{
|
"desired_status": schema.StringAttribute{
|
||||||
Description: "The desired status of the server resource." + utils.SupportedValuesDocumentation(desiredStatusOptions),
|
Description: "The desired status of the server resource. " + utils.SupportedValuesDocumentation(desiredStatusOptions),
|
||||||
Optional: true,
|
Optional: true,
|
||||||
Validators: []validator.String{
|
Validators: []validator.String{
|
||||||
stringvalidator.OneOf(desiredStatusOptions...),
|
stringvalidator.OneOf(desiredStatusOptions...),
|
||||||
|
|
@ -908,6 +941,10 @@ func toCreatePayload(ctx context.Context, model *Model) (*iaas.CreateServerPaylo
|
||||||
Type: conversion.StringValueToPointer(bootVolume.SourceType),
|
Type: conversion.StringValueToPointer(bootVolume.SourceType),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
if !bootVolume.DeleteOnTermination.IsNull() && !bootVolume.DeleteOnTermination.IsUnknown() && bootVolume.DeleteOnTermination.ValueBool() {
|
||||||
|
// it is set and true, adjust payload
|
||||||
|
bootVolumePayload.DeleteOnTermination = conversion.BoolValueToPointer(bootVolume.DeleteOnTermination)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var userData *string
|
var userData *string
|
||||||
|
|
|
||||||
|
|
@ -191,10 +191,11 @@ func TestToCreatePayload(t *testing.T) {
|
||||||
"key": types.StringValue("value"),
|
"key": types.StringValue("value"),
|
||||||
}),
|
}),
|
||||||
BootVolume: types.ObjectValueMust(bootVolumeTypes, map[string]attr.Value{
|
BootVolume: types.ObjectValueMust(bootVolumeTypes, map[string]attr.Value{
|
||||||
"performance_class": types.StringValue("class"),
|
"performance_class": types.StringValue("class"),
|
||||||
"size": types.Int64Value(1),
|
"size": types.Int64Value(1),
|
||||||
"source_type": types.StringValue("type"),
|
"source_type": types.StringValue("type"),
|
||||||
"source_id": types.StringValue("id"),
|
"source_id": types.StringValue("id"),
|
||||||
|
"delete_on_termination": types.BoolUnknown(),
|
||||||
}),
|
}),
|
||||||
ImageId: types.StringValue("image"),
|
ImageId: types.StringValue("image"),
|
||||||
KeypairName: types.StringValue("keypair"),
|
KeypairName: types.StringValue("keypair"),
|
||||||
|
|
@ -222,6 +223,48 @@ func TestToCreatePayload(t *testing.T) {
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"delete on termination is set to true",
|
||||||
|
&Model{
|
||||||
|
Name: types.StringValue("name"),
|
||||||
|
AvailabilityZone: types.StringValue("zone"),
|
||||||
|
Labels: types.MapValueMust(types.StringType, map[string]attr.Value{
|
||||||
|
"key": types.StringValue("value"),
|
||||||
|
}),
|
||||||
|
BootVolume: types.ObjectValueMust(bootVolumeTypes, map[string]attr.Value{
|
||||||
|
"performance_class": types.StringValue("class"),
|
||||||
|
"size": types.Int64Value(1),
|
||||||
|
"source_type": types.StringValue("image"),
|
||||||
|
"source_id": types.StringValue("id"),
|
||||||
|
"delete_on_termination": types.BoolValue(true),
|
||||||
|
}),
|
||||||
|
ImageId: types.StringValue("image"),
|
||||||
|
KeypairName: types.StringValue("keypair"),
|
||||||
|
MachineType: types.StringValue("machine_type"),
|
||||||
|
UserData: types.StringValue(userData),
|
||||||
|
},
|
||||||
|
&iaas.CreateServerPayload{
|
||||||
|
Name: utils.Ptr("name"),
|
||||||
|
AvailabilityZone: utils.Ptr("zone"),
|
||||||
|
Labels: &map[string]interface{}{
|
||||||
|
"key": "value",
|
||||||
|
},
|
||||||
|
BootVolume: &iaas.CreateServerPayloadBootVolume{
|
||||||
|
PerformanceClass: utils.Ptr("class"),
|
||||||
|
Size: utils.Ptr(int64(1)),
|
||||||
|
Source: &iaas.BootVolumeSource{
|
||||||
|
Type: utils.Ptr("image"),
|
||||||
|
Id: utils.Ptr("id"),
|
||||||
|
},
|
||||||
|
DeleteOnTermination: utils.Ptr(true),
|
||||||
|
},
|
||||||
|
ImageId: utils.Ptr("image"),
|
||||||
|
KeypairName: utils.Ptr("keypair"),
|
||||||
|
MachineType: utils.Ptr("machine_type"),
|
||||||
|
UserData: utils.Ptr(base64EncodedUserData),
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.description, func(t *testing.T) {
|
t.Run(tt.description, func(t *testing.T) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue