diff --git a/docs/data-sources/env_aws.md b/docs/data-sources/env_aws.md index e644c87..34d58e1 100644 --- a/docs/data-sources/env_aws.md +++ b/docs/data-sources/env_aws.md @@ -31,6 +31,7 @@ Bring Your Own Cloud (BYOC) AWS environment data source. ### Read-Only +- `allow_delete_while_disconnected` (Boolean) Set to `true` to allow deletion of the environment while it is disconnected from the cloud connect. If the the environment is not connected during the deletion process you will end up in a delete timeout (default `false`). - `aws_account_id` (String) ID of the AWS account ([docs](https://docs.aws.amazon.com/IAM/latest/UserGuide/console_account-alias.html#ViewYourAWSId)) in which to provision AWS resources. **[IMMUTABLE]** - `cidr` (String) VPC CIDR block from the private IPv4 address ranges as specified in RFC 1918 (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16). At least /21 required. **[IMMUTABLE]** diff --git a/docs/data-sources/env_azure.md b/docs/data-sources/env_azure.md index 90cac50..d6dfa49 100644 --- a/docs/data-sources/env_azure.md +++ b/docs/data-sources/env_azure.md @@ -27,6 +27,7 @@ Bring Your Own Cloud (BYOC) Azure environment data source. ### Read-Only +- `allow_delete_while_disconnected` (Boolean) Set to `true` to allow deletion of the environment while it is disconnected from the cloud connect. If the the environment is not connected during the deletion process you will end up in a delete timeout (default `false`). - `cidr` (String) VPC CIDR block from the private IPv4 address ranges as specified in RFC 1918 (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16). At least /21 required. **[IMMUTABLE]** Examples: diff --git a/docs/data-sources/env_gcp.md b/docs/data-sources/env_gcp.md index d79851c..d35256f 100644 --- a/docs/data-sources/env_gcp.md +++ b/docs/data-sources/env_gcp.md @@ -27,6 +27,7 @@ Bring Your Own Cloud (BYOC) GCP environment data source. ### Read-Only +- `allow_delete_while_disconnected` (Boolean) Set to `true` to allow deletion of the environment while it is disconnected from the cloud connect. If the the environment is not connected during the deletion process you will end up in a delete timeout (default `false`). - `cidr` (String) VPC CIDR block from the private IPv4 address ranges as specified in RFC 1918 (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16). At least /21 required. **[IMMUTABLE]** Examples: diff --git a/docs/data-sources/env_hcloud.md b/docs/data-sources/env_hcloud.md index dbb73f1..1f07e19 100644 --- a/docs/data-sources/env_hcloud.md +++ b/docs/data-sources/env_hcloud.md @@ -27,6 +27,7 @@ Bring Your Own Cloud (BYOC) HCloud environment data source. ### Read-Only +- `allow_delete_while_disconnected` (Boolean) Set to `true` to allow deletion of the environment while it is disconnected from the cloud connect. If the the environment is not connected during the deletion process you will end up in a delete timeout (default `false`). - `cidr` (String) VPC CIDR block from the private IPv4 address ranges as specified in RFC 1918 (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16). At least /21 required. **[IMMUTABLE]** Examples: diff --git a/docs/data-sources/env_k8s.md b/docs/data-sources/env_k8s.md index 400b104..7455b60 100644 --- a/docs/data-sources/env_k8s.md +++ b/docs/data-sources/env_k8s.md @@ -27,6 +27,7 @@ Bring Your Own Kubernetes (BYOK) environment data source. ### Read-Only +- `allow_delete_while_disconnected` (Boolean) Set to `true` to allow deletion of the environment while it is disconnected from the cloud connect. If the the environment is not connected during the deletion process you will end up in a delete timeout (default `false`). - `custom_domain` (String) Custom domain. Examples: diff --git a/docs/resources/env_aws.md b/docs/resources/env_aws.md index ffaa485..898bfd9 100644 --- a/docs/resources/env_aws.md +++ b/docs/resources/env_aws.md @@ -230,6 +230,7 @@ resource "aws_vpc_peering_connection_accepter" "peer" { ### Optional +- `allow_delete_while_disconnected` (Boolean) Set to `true` to allow deletion of the environment while it is disconnected from the cloud connect. If the the environment is not connected during the deletion process you will end up in a delete timeout (default `false`). - `cloud_connect` (Boolean) `true` indicates that cloud resources are to be managed via altinity/cloud-connect and `false` means direct management (default `true`). **[IMMUTABLE]** - `custom_domain` (String) Custom domain. diff --git a/docs/resources/env_azure.md b/docs/resources/env_azure.md index 24bb939..0dd101d 100644 --- a/docs/resources/env_azure.md +++ b/docs/resources/env_azure.md @@ -99,6 +99,7 @@ data "altinitycloud_env_azure_status" "this" { ### Optional +- `allow_delete_while_disconnected` (Boolean) Set to `true` to allow deletion of the environment while it is disconnected from the cloud connect. If the the environment is not connected during the deletion process you will end up in a delete timeout (default `false`). - `custom_domain` (String) Custom domain. Examples: diff --git a/docs/resources/env_gcp.md b/docs/resources/env_gcp.md index d8ac1a9..222d0e5 100644 --- a/docs/resources/env_gcp.md +++ b/docs/resources/env_gcp.md @@ -105,6 +105,7 @@ data "altinitycloud_env_gcp_status" "this" { ### Optional +- `allow_delete_while_disconnected` (Boolean) Set to `true` to allow deletion of the environment while it is disconnected from the cloud connect. If the the environment is not connected during the deletion process you will end up in a delete timeout (default `false`). - `custom_domain` (String) Custom domain. Examples: diff --git a/docs/resources/env_hcloud.md b/docs/resources/env_hcloud.md index f5f24f4..fab1628 100644 --- a/docs/resources/env_hcloud.md +++ b/docs/resources/env_hcloud.md @@ -82,6 +82,7 @@ data "altinitycloud_env_hcloud_status" "this" { ### Optional +- `allow_delete_while_disconnected` (Boolean) Set to `true` to allow deletion of the environment while it is disconnected from the cloud connect. If the the environment is not connected during the deletion process you will end up in a delete timeout (default `false`). - `custom_domain` (String) Custom domain. Examples: diff --git a/docs/resources/env_k8s.md b/docs/resources/env_k8s.md index b8556ef..01c06e9 100644 --- a/docs/resources/env_k8s.md +++ b/docs/resources/env_k8s.md @@ -338,6 +338,7 @@ resource "altinitycloud_env_k8s" "this" { ### Optional +- `allow_delete_while_disconnected` (Boolean) Set to `true` to allow deletion of the environment while it is disconnected from the cloud connect. If the the environment is not connected during the deletion process you will end up in a delete timeout (default `false`). - `custom_domain` (String) Custom domain. Examples: diff --git a/internal/provider/common/attributes.go b/internal/provider/common/attributes.go index a0204aa..e2fdd25 100644 --- a/internal/provider/common/attributes.go +++ b/internal/provider/common/attributes.go @@ -207,6 +207,16 @@ func GetSkipProvisioningOnDestroyAttribute(required, optional, computed bool) rs } } +func GetAllowDeleteWhileDisconnectedAttribute(required, optional, computed bool) rschema.BoolAttribute { + return rschema.BoolAttribute{ + Required: required, + Optional: optional, + Computed: computed, + MarkdownDescription: ALLOW_DELETE_WHILE_DISCONNECTED_DESCRIPTION, + Default: booldefault.StaticBool(false), + } +} + func GetReservationsAttribute(required, optional, computed bool) rschema.SetAttribute { return rschema.SetAttribute{ ElementType: types.StringType, diff --git a/internal/provider/common/docs.go b/internal/provider/common/docs.go index 075b978..40e27b4 100644 --- a/internal/provider/common/docs.go +++ b/internal/provider/common/docs.go @@ -92,6 +92,7 @@ const NODE_GROUP_TOLERATIONS_OPERATOR = `Node toleration operator used to match const FORCE_DESTROY_DESCRIPTION = "Locks the environment for accidental deletion when running `terraform destroy` command. Your environment will be deleted, only when setting this parameter to `true`. Once this parameter is set to `true`, there must be a successful `terraform apply` run (before running the `terraform destroy`) to update this value in the state. Without a successful `terraform apply` after this parameter is set, this flag will have no effect. (default `false`)" const FORCE_DESTROY_CLUSTERS_DESCRIPTION = "By default, the destroy operation will not delete any provisioned clusters and the deletion will fail until the clusters get removed. Set to `true` to remove all provisioned clusters as part of the environment deletion process." const SKIP_PROVISIONING_ON_DESTROY_DESCRIPTION = "Set to `true` will delete without waiting for environment deprovisioning. Use this with precaution, it may end up with dangling resources in your cloud provider (default `false`)." +const ALLOW_DELETE_WHILE_DISCONNECTED_DESCRIPTION = "Set to `true` to allow deletion of the environment while it is disconnected from the cloud connect. If the the environment is not connected during the deletion process you will end up in a delete timeout (default `false`)." const STATUS_DESCRIPTION = "Environment status" const STATUS_SPEC_REVISION_DESCRIPTION = "Spec revision" const STATUS_APPLIED_SPEC_REVISION_DESCRIPTION = "Applied spec revision" diff --git a/internal/provider/env/aws/model.go b/internal/provider/env/aws/model.go index 96a7c47..4f7c989 100644 --- a/internal/provider/env/aws/model.go +++ b/internal/provider/env/aws/model.go @@ -27,10 +27,11 @@ type AWSEnvResourceModel struct { CloudConnect types.Bool `tfsdk:"cloud_connect"` MaintenanceWindows []common.MaintenanceWindowModel `tfsdk:"maintenance_windows"` - SpecRevision types.Int64 `tfsdk:"spec_revision"` - ForceDestroy types.Bool `tfsdk:"force_destroy"` - ForceDestroyClusters types.Bool `tfsdk:"force_destroy_clusters"` - SkipDeprovisionOnDestroy types.Bool `tfsdk:"skip_deprovision_on_destroy"` + SpecRevision types.Int64 `tfsdk:"spec_revision"` + ForceDestroy types.Bool `tfsdk:"force_destroy"` + ForceDestroyClusters types.Bool `tfsdk:"force_destroy_clusters"` + SkipDeprovisionOnDestroy types.Bool `tfsdk:"skip_deprovision_on_destroy"` + AllowDeleteWhileDisconnected types.Bool `tfsdk:"allow_delete_while_disconnected"` } type LoadBalancersModel struct { diff --git a/internal/provider/env/aws/resource.go b/internal/provider/env/aws/resource.go index 08565b3..b197add 100644 --- a/internal/provider/env/aws/resource.go +++ b/internal/provider/env/aws/resource.go @@ -151,8 +151,8 @@ func (r *AWSEnvResource) Delete(ctx context.Context, req resource.DeleteRequest, if len(envStatus.AWSEnv.Status.Errors) > 0 { for _, err := range envStatus.AWSEnv.Status.Errors { - if err.Code == "DISCONNECTED" && !data.SkipDeprovisionOnDestroy.ValueBool() { - resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to delete env %s, environment is DISCONNECTED.\nCheck environment's `cloudconnect` or use `skip_deprovision_on_destroy` to delete environment without deprovisioning cloud resources.", envName)) + if err.Code == "DISCONNECTED" && !data.SkipDeprovisionOnDestroy.ValueBool() && !data.AllowDeleteWhileDisconnected.ValueBool() { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to start env %s, environment is DISCONNECTED.\nCheck environment's `cloudconnect` or use `allow_delete_while_disconnected=true` to continue with the delete operation.", envName)) return } } diff --git a/internal/provider/env/aws/schema.go b/internal/provider/env/aws/schema.go index db68530..1057aec 100644 --- a/internal/provider/env/aws/schema.go +++ b/internal/provider/env/aws/schema.go @@ -25,26 +25,27 @@ func (r *AWSEnvResource) Schema(ctx context.Context, req resource.SchemaRequest, resp.Schema = rschema.Schema{ MarkdownDescription: heredoc.Doc(`Bring Your Own Cloud (BYOC) AWS environment resource.`), Attributes: map[string]rschema.Attribute{ - "id": common.IDAttribute, - "name": common.NameAttribute, - "custom_domain": common.GetCommonCustomDomainAttribute(false, true, false), - "load_balancers": getLoadBalancersAttribute(false, true, true), - "load_balancing_strategy": common.GetLoadBalancingStrategyAttribute(false, true, true), - "maintenance_windows": common.GetMaintenanceWindowAttribute(false, true, false), - "cidr": common.GetCIDRAttribute(true, false, false), - "zones": getZonesAttribute(false, true, true, common.AWS_ZONES_DESCRIPTION), - "node_groups": common.GetNodeGroupsAttribute(true, false, false), - "aws_account_id": getAWSAccountIDAttribute(true, false, false), - "region": common.GetRegionAttribute(true, false, false, common.AWS_REGION_DESCRIPTION), - "nat": getNATAttribute(false, true, true), - "peering_connections": getPeeringConnectionsAttribute(false, true, false), - "endpoints": getEndpointsAttribute(false, true, false), - "tags": getTagsAttribute(false, true, false), - "cloud_connect": getCloudConnectAttribute(false, true, true), - "spec_revision": common.SpecRevisionAttribute, - "force_destroy": common.GetForceDestroyAttribute(false, true, true), - "force_destroy_clusters": common.GetForceDestroyClustersAttribute(false, true, true), - "skip_deprovision_on_destroy": common.GetSkipProvisioningOnDestroyAttribute(false, true, true), + "id": common.IDAttribute, + "name": common.NameAttribute, + "custom_domain": common.GetCommonCustomDomainAttribute(false, true, false), + "load_balancers": getLoadBalancersAttribute(false, true, true), + "load_balancing_strategy": common.GetLoadBalancingStrategyAttribute(false, true, true), + "maintenance_windows": common.GetMaintenanceWindowAttribute(false, true, false), + "cidr": common.GetCIDRAttribute(true, false, false), + "zones": getZonesAttribute(false, true, true, common.AWS_ZONES_DESCRIPTION), + "node_groups": common.GetNodeGroupsAttribute(true, false, false), + "aws_account_id": getAWSAccountIDAttribute(true, false, false), + "region": common.GetRegionAttribute(true, false, false, common.AWS_REGION_DESCRIPTION), + "nat": getNATAttribute(false, true, true), + "peering_connections": getPeeringConnectionsAttribute(false, true, false), + "endpoints": getEndpointsAttribute(false, true, false), + "tags": getTagsAttribute(false, true, false), + "cloud_connect": getCloudConnectAttribute(false, true, true), + "spec_revision": common.SpecRevisionAttribute, + "force_destroy": common.GetForceDestroyAttribute(false, true, true), + "force_destroy_clusters": common.GetForceDestroyClustersAttribute(false, true, true), + "skip_deprovision_on_destroy": common.GetSkipProvisioningOnDestroyAttribute(false, true, true), + "allow_delete_while_disconnected": common.GetAllowDeleteWhileDisconnectedAttribute(false, true, true), }, } } @@ -73,9 +74,10 @@ func (d *AWSEnvDataSource) Schema(ctx context.Context, req datasource.SchemaRequ // these options are not used in data sources, // but we need to include them in the schema to avoid conversion errors. - "force_destroy": common.GetForceDestroyAttribute(false, false, true), - "force_destroy_clusters": common.GetForceDestroyClustersAttribute(false, false, true), - "skip_deprovision_on_destroy": common.GetSkipProvisioningOnDestroyAttribute(false, false, true), + "force_destroy": common.GetForceDestroyAttribute(false, false, true), + "force_destroy_clusters": common.GetForceDestroyClustersAttribute(false, false, true), + "skip_deprovision_on_destroy": common.GetSkipProvisioningOnDestroyAttribute(false, false, true), + "allow_delete_while_disconnected": common.GetAllowDeleteWhileDisconnectedAttribute(false, false, true), }, } } diff --git a/internal/provider/env/azure/model.go b/internal/provider/env/azure/model.go index 75b8165..86a6c4d 100644 --- a/internal/provider/env/azure/model.go +++ b/internal/provider/env/azure/model.go @@ -24,10 +24,11 @@ type AzureEnvResourceModel struct { Tags []common.KeyValueModel `tfsdk:"tags"` PrivateLinkService *PrivateLinkServiceModel `tfsdk:"private_link_service"` - SpecRevision types.Int64 `tfsdk:"spec_revision"` - ForceDestroy types.Bool `tfsdk:"force_destroy"` - ForceDestroyClusters types.Bool `tfsdk:"force_destroy_clusters"` - SkipDeprovisionOnDestroy types.Bool `tfsdk:"skip_deprovision_on_destroy"` + SpecRevision types.Int64 `tfsdk:"spec_revision"` + ForceDestroy types.Bool `tfsdk:"force_destroy"` + ForceDestroyClusters types.Bool `tfsdk:"force_destroy_clusters"` + SkipDeprovisionOnDestroy types.Bool `tfsdk:"skip_deprovision_on_destroy"` + AllowDeleteWhileDisconnected types.Bool `tfsdk:"allow_delete_while_disconnected"` } type PrivateLinkServiceModel struct { diff --git a/internal/provider/env/azure/resource.go b/internal/provider/env/azure/resource.go index 2a17a5c..21317e6 100644 --- a/internal/provider/env/azure/resource.go +++ b/internal/provider/env/azure/resource.go @@ -153,8 +153,8 @@ func (r *AzureEnvResource) Delete(ctx context.Context, req resource.DeleteReques if len(envStatus.AzureEnv.Status.Errors) > 0 { for _, err := range envStatus.AzureEnv.Status.Errors { - if err.Code == "DISCONNECTED" && !data.SkipDeprovisionOnDestroy.ValueBool() { - resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to delete env %s, environment is DISCONNECTED.\nCheck environment's `cloudconnect` or use `skip_deprovision_on_destroy` to delete environment without deprovisioning cloud resources.", envName)) + if err.Code == "DISCONNECTED" && !data.SkipDeprovisionOnDestroy.ValueBool() && !data.AllowDeleteWhileDisconnected.ValueBool() { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to start env %s, environment is DISCONNECTED.\nCheck environment's `cloudconnect` or use `allow_delete_while_disconnected=true` to continue with the delete operation.", envName)) return } } diff --git a/internal/provider/env/azure/schema.go b/internal/provider/env/azure/schema.go index dc004db..6764544 100644 --- a/internal/provider/env/azure/schema.go +++ b/internal/provider/env/azure/schema.go @@ -22,24 +22,25 @@ func (r *AzureEnvResource) Schema(ctx context.Context, req resource.SchemaReques resp.Schema = rschema.Schema{ MarkdownDescription: heredoc.Doc(`Bring Your Own Cloud (BYOC) Azure environment resource.`), Attributes: map[string]rschema.Attribute{ - "id": common.IDAttribute, - "name": common.NameAttribute, - "custom_domain": getCustomDomainAttribute(false, true, false), - "load_balancers": getLoadBalancersAttribute(false, true, true), - "load_balancing_strategy": common.GetLoadBalancingStrategyAttribute(false, true, true), - "maintenance_windows": common.GetMaintenanceWindowAttribute(false, true, false), - "cidr": common.GetCIDRAttribute(true, false, false), - "zones": common.GetZonesAttribute(false, true, true, common.AZURE_ZONES_DESCRIPTION), - "node_groups": common.GetNodeGroupsAttribute(true, false, false), - "region": common.GetRegionAttribute(true, false, false, common.AZURE_REGION_DESCRIPTION), - "tenant_id": getAzureTenantIDAttribute(true, false, false), - "subscription_id": getAzureSubscriptionIDAttribute(true, false, false), - "tags": getTagsAttribute(false, true, false), - "private_link_service": getPrivateLinkServiceAttribute(false, true, true), - "spec_revision": common.SpecRevisionAttribute, - "force_destroy": common.GetForceDestroyAttribute(false, true, true), - "force_destroy_clusters": common.GetForceDestroyClustersAttribute(false, true, true), - "skip_deprovision_on_destroy": common.GetSkipProvisioningOnDestroyAttribute(false, true, true), + "id": common.IDAttribute, + "name": common.NameAttribute, + "custom_domain": getCustomDomainAttribute(false, true, false), + "load_balancers": getLoadBalancersAttribute(false, true, true), + "load_balancing_strategy": common.GetLoadBalancingStrategyAttribute(false, true, true), + "maintenance_windows": common.GetMaintenanceWindowAttribute(false, true, false), + "cidr": common.GetCIDRAttribute(true, false, false), + "zones": common.GetZonesAttribute(false, true, true, common.AZURE_ZONES_DESCRIPTION), + "node_groups": common.GetNodeGroupsAttribute(true, false, false), + "region": common.GetRegionAttribute(true, false, false, common.AZURE_REGION_DESCRIPTION), + "tenant_id": getAzureTenantIDAttribute(true, false, false), + "subscription_id": getAzureSubscriptionIDAttribute(true, false, false), + "tags": getTagsAttribute(false, true, false), + "private_link_service": getPrivateLinkServiceAttribute(false, true, true), + "spec_revision": common.SpecRevisionAttribute, + "force_destroy": common.GetForceDestroyAttribute(false, true, true), + "force_destroy_clusters": common.GetForceDestroyClustersAttribute(false, true, true), + "skip_deprovision_on_destroy": common.GetSkipProvisioningOnDestroyAttribute(false, true, true), + "allow_delete_while_disconnected": common.GetAllowDeleteWhileDisconnectedAttribute(false, true, true), }, } } @@ -66,9 +67,10 @@ func (d *AzureEnvDataSource) Schema(ctx context.Context, req datasource.SchemaRe // these options are not used in data sources, // but we need to include them in the schema to avoid conversion errors. - "force_destroy": common.GetForceDestroyAttribute(false, false, true), - "force_destroy_clusters": common.GetForceDestroyClustersAttribute(false, false, true), - "skip_deprovision_on_destroy": common.GetSkipProvisioningOnDestroyAttribute(false, false, true), + "force_destroy": common.GetForceDestroyAttribute(false, false, true), + "force_destroy_clusters": common.GetForceDestroyClustersAttribute(false, false, true), + "skip_deprovision_on_destroy": common.GetSkipProvisioningOnDestroyAttribute(false, false, true), + "allow_delete_while_disconnected": common.GetAllowDeleteWhileDisconnectedAttribute(false, false, true), }, } } diff --git a/internal/provider/env/gcp/model.go b/internal/provider/env/gcp/model.go index 64dcc59..6b7830b 100644 --- a/internal/provider/env/gcp/model.go +++ b/internal/provider/env/gcp/model.go @@ -22,10 +22,11 @@ type GCPEnvResourceModel struct { LoadBalancingStrategy types.String `tfsdk:"load_balancing_strategy"` MaintenanceWindows []common.MaintenanceWindowModel `tfsdk:"maintenance_windows"` - SpecRevision types.Int64 `tfsdk:"spec_revision"` - ForceDestroy types.Bool `tfsdk:"force_destroy"` - ForceDestroyClusters types.Bool `tfsdk:"force_destroy_clusters"` - SkipDeprovisionOnDestroy types.Bool `tfsdk:"skip_deprovision_on_destroy"` + SpecRevision types.Int64 `tfsdk:"spec_revision"` + ForceDestroy types.Bool `tfsdk:"force_destroy"` + ForceDestroyClusters types.Bool `tfsdk:"force_destroy_clusters"` + SkipDeprovisionOnDestroy types.Bool `tfsdk:"skip_deprovision_on_destroy"` + AllowDeleteWhileDisconnected types.Bool `tfsdk:"allow_delete_while_disconnected"` } type LoadBalancersModel struct { diff --git a/internal/provider/env/gcp/resource.go b/internal/provider/env/gcp/resource.go index 51f1f20..73881d8 100644 --- a/internal/provider/env/gcp/resource.go +++ b/internal/provider/env/gcp/resource.go @@ -153,8 +153,8 @@ func (r *GCPEnvResource) Delete(ctx context.Context, req resource.DeleteRequest, if len(envStatus.GCPEnv.Status.Errors) > 0 { for _, err := range envStatus.GCPEnv.Status.Errors { - if err.Code == "DISCONNECTED" && !data.SkipDeprovisionOnDestroy.ValueBool() { - resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to delete env %s, environment is DISCONNECTED.\nCheck environment's `cloudconnect` or use `skip_deprovision_on_destroy` to delete environment without deprovisioning cloud resources.", envName)) + if err.Code == "DISCONNECTED" && !data.SkipDeprovisionOnDestroy.ValueBool() && !data.AllowDeleteWhileDisconnected.ValueBool() { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to start env %s, environment is DISCONNECTED.\nCheck environment's `cloudconnect` or use `allow_delete_while_disconnected=true` to continue with the delete operation.", envName)) return } } diff --git a/internal/provider/env/gcp/schema.go b/internal/provider/env/gcp/schema.go index d5541e9..c93a099 100644 --- a/internal/provider/env/gcp/schema.go +++ b/internal/provider/env/gcp/schema.go @@ -20,21 +20,22 @@ func (r *GCPEnvResource) Schema(ctx context.Context, req resource.SchemaRequest, resp.Schema = rschema.Schema{ MarkdownDescription: heredoc.Doc(`Bring Your Own Cloud (BYOC) GCP environment resource.`), Attributes: map[string]rschema.Attribute{ - "id": common.IDAttribute, - "name": common.NameAttribute, - "custom_domain": common.GetCommonCustomDomainAttribute(false, true, false), - "load_balancers": getLoadBalancersAttribute(false, true, true), - "load_balancing_strategy": common.GetLoadBalancingStrategyAttribute(false, true, true), - "maintenance_windows": common.GetMaintenanceWindowAttribute(false, true, false), - "cidr": common.GetCIDRAttribute(true, false, false), - "zones": common.GetZonesAttribute(false, true, true, common.GCP_ZONES_DESCRIPTION), - "node_groups": common.GetNodeGroupsAttribute(true, false, false), - "region": common.GetRegionAttribute(true, false, false, common.GCP_REGION_DESCRIPTION), - "gcp_project_id": getGCPProjectIDAttribute(true, false, false), - "spec_revision": common.SpecRevisionAttribute, - "force_destroy": common.GetForceDestroyAttribute(false, true, true), - "force_destroy_clusters": common.GetForceDestroyClustersAttribute(false, true, true), - "skip_deprovision_on_destroy": common.GetSkipProvisioningOnDestroyAttribute(false, true, true), + "id": common.IDAttribute, + "name": common.NameAttribute, + "custom_domain": common.GetCommonCustomDomainAttribute(false, true, false), + "load_balancers": getLoadBalancersAttribute(false, true, true), + "load_balancing_strategy": common.GetLoadBalancingStrategyAttribute(false, true, true), + "maintenance_windows": common.GetMaintenanceWindowAttribute(false, true, false), + "cidr": common.GetCIDRAttribute(true, false, false), + "zones": common.GetZonesAttribute(false, true, true, common.GCP_ZONES_DESCRIPTION), + "node_groups": common.GetNodeGroupsAttribute(true, false, false), + "region": common.GetRegionAttribute(true, false, false, common.GCP_REGION_DESCRIPTION), + "gcp_project_id": getGCPProjectIDAttribute(true, false, false), + "spec_revision": common.SpecRevisionAttribute, + "force_destroy": common.GetForceDestroyAttribute(false, true, true), + "force_destroy_clusters": common.GetForceDestroyClustersAttribute(false, true, true), + "skip_deprovision_on_destroy": common.GetSkipProvisioningOnDestroyAttribute(false, true, true), + "allow_delete_while_disconnected": common.GetAllowDeleteWhileDisconnectedAttribute(false, true, true), }, } } @@ -58,9 +59,10 @@ func (d *GCPEnvDataSource) Schema(ctx context.Context, req datasource.SchemaRequ // these options are not used in data sources, // but we need to include them in the schema to avoid conversion errors. - "force_destroy": common.GetForceDestroyAttribute(false, false, true), - "force_destroy_clusters": common.GetForceDestroyClustersAttribute(false, false, true), - "skip_deprovision_on_destroy": common.GetSkipProvisioningOnDestroyAttribute(false, false, true), + "force_destroy": common.GetForceDestroyAttribute(false, false, true), + "force_destroy_clusters": common.GetForceDestroyClustersAttribute(false, false, true), + "skip_deprovision_on_destroy": common.GetSkipProvisioningOnDestroyAttribute(false, false, true), + "allow_delete_while_disconnected": common.GetAllowDeleteWhileDisconnectedAttribute(false, false, true), }, } } diff --git a/internal/provider/env/hcloud/model.go b/internal/provider/env/hcloud/model.go index 478151f..cbd377a 100644 --- a/internal/provider/env/hcloud/model.go +++ b/internal/provider/env/hcloud/model.go @@ -22,10 +22,11 @@ type HCloudEnvResourceModel struct { MaintenanceWindows []common.MaintenanceWindowModel `tfsdk:"maintenance_windows"` WireguardPeers []WireguardPeers `tfsdk:"wireguard_peers"` - SpecRevision types.Int64 `tfsdk:"spec_revision"` - ForceDestroy types.Bool `tfsdk:"force_destroy"` - ForceDestroyClusters types.Bool `tfsdk:"force_destroy_clusters"` - SkipDeprovisionOnDestroy types.Bool `tfsdk:"skip_deprovision_on_destroy"` + SpecRevision types.Int64 `tfsdk:"spec_revision"` + ForceDestroy types.Bool `tfsdk:"force_destroy"` + ForceDestroyClusters types.Bool `tfsdk:"force_destroy_clusters"` + SkipDeprovisionOnDestroy types.Bool `tfsdk:"skip_deprovision_on_destroy"` + AllowDeleteWhileDisconnected types.Bool `tfsdk:"allow_delete_while_disconnected"` } type LoadBalancersModel struct { diff --git a/internal/provider/env/hcloud/resource.go b/internal/provider/env/hcloud/resource.go index cb1ded0..295cca9 100644 --- a/internal/provider/env/hcloud/resource.go +++ b/internal/provider/env/hcloud/resource.go @@ -153,8 +153,8 @@ func (r *HCloudEnvResource) Delete(ctx context.Context, req resource.DeleteReque if len(envStatus.HcloudEnv.Status.Errors) > 0 { for _, err := range envStatus.HcloudEnv.Status.Errors { - if err.Code == "DISCONNECTED" { - resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to delete env %s, environment is DISCONNECTED", envName)) + if err.Code == "DISCONNECTED" && !data.SkipDeprovisionOnDestroy.ValueBool() && !data.AllowDeleteWhileDisconnected.ValueBool() { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to start env %s, environment is DISCONNECTED.\nCheck environment's `cloudconnect` or use `allow_delete_while_disconnected=true` to continue with the delete operation.", envName)) return } } diff --git a/internal/provider/env/hcloud/schema.go b/internal/provider/env/hcloud/schema.go index b485a74..0d396db 100644 --- a/internal/provider/env/hcloud/schema.go +++ b/internal/provider/env/hcloud/schema.go @@ -25,22 +25,23 @@ func (r *HCloudEnvResource) Schema(ctx context.Context, req resource.SchemaReque resp.Schema = rschema.Schema{ MarkdownDescription: heredoc.Doc(`Bring Your Own Cloud (BYOC) HCloud environment resource.`), Attributes: map[string]rschema.Attribute{ - "id": common.IDAttribute, - "name": common.NameAttribute, - "hcloud_token_enc": getHCloudTokenEncAttribute(true, false, false), - "custom_domain": common.GetCommonCustomDomainAttribute(false, true, false), - "load_balancers": getLoadBalancersAttribute(false, true, true), - "load_balancing_strategy": common.GetLoadBalancingStrategyAttribute(false, true, true), - "maintenance_windows": common.GetMaintenanceWindowAttribute(false, true, false), - "cidr": common.GetCIDRAttribute(true, false, false), - "locations": common.GetZonesAttribute(false, true, true, common.HCLOUD_LOCATIONS_DESCRIPTION), - "node_groups": getNodeGroupsAttribute(true, false, false), - "network_zone": common.GetRegionAttribute(true, false, false, common.HCLOUD_NETWORK_ZONE_DESCRIPTION), - "wireguard_peers": getWireguardPeersAttribute(false, true, false), - "spec_revision": common.SpecRevisionAttribute, - "force_destroy": common.GetForceDestroyAttribute(false, true, true), - "force_destroy_clusters": common.GetForceDestroyClustersAttribute(false, true, true), - "skip_deprovision_on_destroy": common.GetSkipProvisioningOnDestroyAttribute(false, true, true), + "id": common.IDAttribute, + "name": common.NameAttribute, + "hcloud_token_enc": getHCloudTokenEncAttribute(true, false, false), + "custom_domain": common.GetCommonCustomDomainAttribute(false, true, false), + "load_balancers": getLoadBalancersAttribute(false, true, true), + "load_balancing_strategy": common.GetLoadBalancingStrategyAttribute(false, true, true), + "maintenance_windows": common.GetMaintenanceWindowAttribute(false, true, false), + "cidr": common.GetCIDRAttribute(true, false, false), + "locations": common.GetZonesAttribute(false, true, true, common.HCLOUD_LOCATIONS_DESCRIPTION), + "node_groups": getNodeGroupsAttribute(true, false, false), + "network_zone": common.GetRegionAttribute(true, false, false, common.HCLOUD_NETWORK_ZONE_DESCRIPTION), + "wireguard_peers": getWireguardPeersAttribute(false, true, false), + "spec_revision": common.SpecRevisionAttribute, + "force_destroy": common.GetForceDestroyAttribute(false, true, true), + "force_destroy_clusters": common.GetForceDestroyClustersAttribute(false, true, true), + "skip_deprovision_on_destroy": common.GetSkipProvisioningOnDestroyAttribute(false, true, true), + "allow_delete_while_disconnected": common.GetAllowDeleteWhileDisconnectedAttribute(false, true, true), }, } } @@ -65,9 +66,10 @@ func (d *HCloudEnvDataSource) Schema(ctx context.Context, req datasource.SchemaR // these options are not used in data sources, // but we need to include them in the schema to avoid conversion errors. - "force_destroy": common.GetForceDestroyAttribute(false, false, true), - "force_destroy_clusters": common.GetForceDestroyClustersAttribute(false, false, true), - "skip_deprovision_on_destroy": common.GetSkipProvisioningOnDestroyAttribute(false, false, true), + "force_destroy": common.GetForceDestroyAttribute(false, false, true), + "force_destroy_clusters": common.GetForceDestroyClustersAttribute(false, false, true), + "skip_deprovision_on_destroy": common.GetSkipProvisioningOnDestroyAttribute(false, false, true), + "allow_delete_while_disconnected": common.GetAllowDeleteWhileDisconnectedAttribute(false, false, true), }, } } diff --git a/internal/provider/env/k8s/model.go b/internal/provider/env/k8s/model.go index 6da5b13..7c8a2b8 100644 --- a/internal/provider/env/k8s/model.go +++ b/internal/provider/env/k8s/model.go @@ -21,10 +21,11 @@ type K8SEnvResourceModel struct { Metrics *MetricsModel `tfsdk:"metrics"` MaintenanceWindows []common.MaintenanceWindowModel `tfsdk:"maintenance_windows"` - SpecRevision types.Int64 `tfsdk:"spec_revision"` - ForceDestroy types.Bool `tfsdk:"force_destroy"` - ForceDestroyClusters types.Bool `tfsdk:"force_destroy_clusters"` - SkipDeprovisionOnDestroy types.Bool `tfsdk:"skip_deprovision_on_destroy"` + SpecRevision types.Int64 `tfsdk:"spec_revision"` + ForceDestroy types.Bool `tfsdk:"force_destroy"` + ForceDestroyClusters types.Bool `tfsdk:"force_destroy_clusters"` + SkipDeprovisionOnDestroy types.Bool `tfsdk:"skip_deprovision_on_destroy"` + AllowDeleteWhileDisconnected types.Bool `tfsdk:"allow_delete_while_disconnected"` } type LogsModel struct { diff --git a/internal/provider/env/k8s/resource.go b/internal/provider/env/k8s/resource.go index 3332e5d..51eb036 100644 --- a/internal/provider/env/k8s/resource.go +++ b/internal/provider/env/k8s/resource.go @@ -150,8 +150,8 @@ func (r *K8SEnvResource) Delete(ctx context.Context, req resource.DeleteRequest, if len(envStatus.K8sEnv.Status.Errors) > 0 { for _, err := range envStatus.K8sEnv.Status.Errors { - if err.Code == "DISCONNECTED" && !data.SkipDeprovisionOnDestroy.ValueBool() { - resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to delete env %s, environment is DISCONNECTED.\nCheck environment's `cloudconnect` or use `skip_deprovision_on_destroy` to delete environment without deprovisioning cloud resources.", envName)) + if err.Code == "DISCONNECTED" && !data.SkipDeprovisionOnDestroy.ValueBool() && !data.AllowDeleteWhileDisconnected.ValueBool() { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to start env %s, environment is DISCONNECTED.\nCheck environment's `cloudconnect` or use `allow_delete_while_disconnected=true` to continue with the delete operation.", envName)) return } } diff --git a/internal/provider/env/k8s/schema.go b/internal/provider/env/k8s/schema.go index 6c694cd..adff478 100644 --- a/internal/provider/env/k8s/schema.go +++ b/internal/provider/env/k8s/schema.go @@ -26,21 +26,22 @@ func (r *K8SEnvResource) Schema(ctx context.Context, req resource.SchemaRequest, resp.Schema = rschema.Schema{ MarkdownDescription: heredoc.Doc(`Bring Your Own Kubernetes (BYOK) environment resource.`), Attributes: map[string]rschema.Attribute{ - "id": common.IDAttribute, - "name": common.NameAttribute, - "custom_domain": common.GetCommonCustomDomainAttribute(false, true, false), - "load_balancers": getLoadBalancersAttribute(false, true, true), - "load_balancing_strategy": common.GetLoadBalancingStrategyAttribute(false, true, true), - "maintenance_windows": common.GetMaintenanceWindowAttribute(false, true, false), - "logs": getLogsAttributes(false, true, true), - "metrics": getMetricsAttribute(false, true, true), - "distribution": getDistributionAttribute(true, false, false), - "node_groups": getNodeGroupsAttribute(true, false, false), - "custom_node_types": getCustomNodeTypes(false, true, false), - "spec_revision": common.SpecRevisionAttribute, - "force_destroy": common.GetForceDestroyAttribute(false, true, true), - "force_destroy_clusters": common.GetForceDestroyClustersAttribute(false, true, true), - "skip_deprovision_on_destroy": common.GetSkipProvisioningOnDestroyAttribute(false, true, true), + "id": common.IDAttribute, + "name": common.NameAttribute, + "custom_domain": common.GetCommonCustomDomainAttribute(false, true, false), + "load_balancers": getLoadBalancersAttribute(false, true, true), + "load_balancing_strategy": common.GetLoadBalancingStrategyAttribute(false, true, true), + "maintenance_windows": common.GetMaintenanceWindowAttribute(false, true, false), + "logs": getLogsAttributes(false, true, true), + "metrics": getMetricsAttribute(false, true, true), + "distribution": getDistributionAttribute(true, false, false), + "node_groups": getNodeGroupsAttribute(true, false, false), + "custom_node_types": getCustomNodeTypes(false, true, false), + "spec_revision": common.SpecRevisionAttribute, + "force_destroy": common.GetForceDestroyAttribute(false, true, true), + "force_destroy_clusters": common.GetForceDestroyClustersAttribute(false, true, true), + "skip_deprovision_on_destroy": common.GetSkipProvisioningOnDestroyAttribute(false, true, true), + "allow_delete_while_disconnected": common.GetAllowDeleteWhileDisconnectedAttribute(false, true, true), }, } } @@ -64,9 +65,10 @@ func (d *K8SEnvDataSource) Schema(ctx context.Context, req datasource.SchemaRequ // these options are not used in data sources, // but we need to include them in the schema to avoid conversion errors. - "force_destroy": common.GetForceDestroyAttribute(false, false, true), - "force_destroy_clusters": common.GetForceDestroyClustersAttribute(false, false, true), - "skip_deprovision_on_destroy": common.GetSkipProvisioningOnDestroyAttribute(false, false, true), + "force_destroy": common.GetForceDestroyAttribute(false, false, true), + "force_destroy_clusters": common.GetForceDestroyClustersAttribute(false, false, true), + "skip_deprovision_on_destroy": common.GetSkipProvisioningOnDestroyAttribute(false, false, true), + "allow_delete_while_disconnected": common.GetAllowDeleteWhileDisconnectedAttribute(false, false, true), }, } }