Compare commits

..

2 Commits

Author SHA1 Message Date
dependabot[bot] cd85f67e28 🐹 Bump github.com/hashicorp/terraform-plugin-testing (#47)
Bumps the minor-patch group with 1 update: [github.com/hashicorp/terraform-plugin-testing](https://github.com/hashicorp/terraform-plugin-testing).


Updates `github.com/hashicorp/terraform-plugin-testing` from 1.10.0 to 1.11.0
- [Release notes](https://github.com/hashicorp/terraform-plugin-testing/releases)
- [Changelog](https://github.com/hashicorp/terraform-plugin-testing/blob/main/CHANGELOG.md)
- [Commits](https://github.com/hashicorp/terraform-plugin-testing/compare/v1.10.0...v1.11.0)

---
updated-dependencies:
- dependency-name: github.com/hashicorp/terraform-plugin-testing
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-22 10:12:43 +08:00
Oscar Hermoso 50d06b967b 🐣 source_and_destination_check for server resource (#48)
* 🐣 source_and_destination_check for server resource

* Ensure default values are handled correctly
2024-11-22 10:12:22 +08:00
7 changed files with 166 additions and 48 deletions
+1
View File
@@ -28,6 +28,7 @@ Provides a Binary Lane Server resource. This can be used to create and delete se
- `name` (String) The hostname of your server, such as vps01.yourcompany.com. If not provided, the server will be created with a random name.
- `password` (String, Sensitive) If this is provided the specified or default remote user's account password will be set to this value. Only valid if the server supports password change actions. If omitted and the server supports password change actions a random password will be generated and emailed to the account email address.
- `port_blocking` (Boolean) Port blocking of outgoing connections for email, SSH and Remote Desktop (TCP ports 22, 25, and 3389) is enabled by default for all new servers. If this is false port blocking will be disabled. Disabling port blocking is only available to reviewed accounts.
- `source_and_destination_check` (Boolean) This attribute can only be set if your server also has a `vpc_id` attribute set. When enabled (which is `true` by default), your server will only be able to send or receive packets that are directly addressed to one of the IP addresses associated with the Cloud Server. Generally, this is desirable behaviour because it prevents IP conflicts and other hard-to-diagnose networking faults due to incorrect network configuration. When `source_and_destination_check` is `false`, your Cloud Server will be able to send and receive packets addressed to any server. This is typically used when you want to use your Cloud Server as a VPN endpoint, a NAT server to provide internet access, or IP forwarding.
- `ssh_keys` (List of Number) This is a list of SSH key ids. If this is null or not provided, any SSH keys that have been marked as default will be deployed (assuming the operating system supports SSH Keys). Submit an empty list to disable deployment of default keys.
- `timeouts` (Attributes) (see [below for nested schema](#nestedatt--timeouts))
- `user_data` (String) If provided this will be used to initialise the new server. This must be left null if the Image does not support UserData, see DistributionInfo.Features for more information.
+7 -6
View File
@@ -35,12 +35,13 @@ resource "binarylane_server" "db" {
# VPN server
resource "binarylane_server" "vpn" {
name = "tf-example-vpc-vpn"
region = "per"
image = "ubuntu-24.04"
size = "std-min"
vpc_id = binarylane_vpc.example.id
public_ipv4_count = 1
name = "tf-example-vpc-vpn"
region = "per"
image = "ubuntu-24.04"
size = "std-min"
vpc_id = binarylane_vpc.example.id
public_ipv4_count = 1
source_and_destination_check = false
}
resource "binarylane_vpc_route_entries" "example" {
+7 -7
View File
@@ -12,7 +12,7 @@ require (
github.com/hashicorp/terraform-plugin-framework-validators v0.15.0
github.com/hashicorp/terraform-plugin-go v0.25.0
github.com/hashicorp/terraform-plugin-log v0.9.0
github.com/hashicorp/terraform-plugin-testing v1.10.0
github.com/hashicorp/terraform-plugin-testing v1.11.0
github.com/oapi-codegen/oapi-codegen/v2 v2.4.1
github.com/oapi-codegen/runtime v1.1.1
)
@@ -55,12 +55,12 @@ require (
github.com/hashicorp/go-uuid v1.0.3 // indirect
github.com/hashicorp/go-version v1.7.0 // indirect
github.com/hashicorp/hc-install v0.9.0 // indirect
github.com/hashicorp/hcl/v2 v2.21.0 // indirect
github.com/hashicorp/hcl/v2 v2.23.0 // indirect
github.com/hashicorp/logutils v1.0.0 // indirect
github.com/hashicorp/terraform-exec v0.21.0 // indirect
github.com/hashicorp/terraform-json v0.23.0 // indirect
github.com/hashicorp/terraform-plugin-codegen-spec v0.2.0 // indirect
github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0 // indirect
github.com/hashicorp/terraform-plugin-sdk/v2 v2.35.0 // indirect
github.com/hashicorp/terraform-registry-address v0.2.3 // indirect
github.com/hashicorp/terraform-svchost v0.1.1 // indirect
github.com/hashicorp/yamux v0.1.2 // indirect
@@ -99,13 +99,13 @@ require (
github.com/yuin/goldmark-meta v1.1.0 // indirect
github.com/zclconf/go-cty v1.15.0 // indirect
go.abhg.dev/goldmark/frontmatter v0.2.0 // indirect
golang.org/x/crypto v0.28.0 // indirect
golang.org/x/crypto v0.29.0 // indirect
golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 // indirect
golang.org/x/mod v0.21.0 // indirect
golang.org/x/net v0.30.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.26.0 // indirect
golang.org/x/text v0.19.0 // indirect
golang.org/x/sync v0.9.0 // indirect
golang.org/x/sys v0.27.0 // indirect
golang.org/x/text v0.20.0 // indirect
golang.org/x/tools v0.22.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 // indirect
+14 -14
View File
@@ -131,8 +131,8 @@ github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKe
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/hc-install v0.9.0 h1:2dIk8LcvANwtv3QZLckxcjyF5w8KVtiMxu6G6eLhghE=
github.com/hashicorp/hc-install v0.9.0/go.mod h1:+6vOP+mf3tuGgMApVYtmsnDoKWMDcFXeTxCACYZ8SFg=
github.com/hashicorp/hcl/v2 v2.21.0 h1:lve4q/o/2rqwYOgUg3y3V2YPyD1/zkCLGjIV74Jit14=
github.com/hashicorp/hcl/v2 v2.21.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA=
github.com/hashicorp/hcl/v2 v2.23.0 h1:Fphj1/gCylPxHutVSEOf2fBOh1VE4AuLV7+kbJf3qos=
github.com/hashicorp/hcl/v2 v2.23.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA=
github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/terraform-exec v0.21.0 h1:uNkLAe95ey5Uux6KJdua6+cv8asgILFVWkd/RG0D2XQ=
@@ -157,10 +157,10 @@ github.com/hashicorp/terraform-plugin-go v0.25.0 h1:oi13cx7xXA6QciMcpcFi/rwA974r
github.com/hashicorp/terraform-plugin-go v0.25.0/go.mod h1:+SYagMYadJP86Kvn+TGeV+ofr/R3g4/If0O5sO96MVw=
github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0=
github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow=
github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0 h1:kJiWGx2kiQVo97Y5IOGR4EMcZ8DtMswHhUuFibsCQQE=
github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0/go.mod h1:sl/UoabMc37HA6ICVMmGO+/0wofkVIRxf+BMb/dnoIg=
github.com/hashicorp/terraform-plugin-testing v1.10.0 h1:2+tmRNhvnfE4Bs8rB6v58S/VpqzGC6RCh9Y8ujdn+aw=
github.com/hashicorp/terraform-plugin-testing v1.10.0/go.mod h1:iWRW3+loP33WMch2P/TEyCxxct/ZEcCGMquSLSCVsrc=
github.com/hashicorp/terraform-plugin-sdk/v2 v2.35.0 h1:wyKCCtn6pBBL46c1uIIBNUOWlNfYXfXpVo16iDyLp8Y=
github.com/hashicorp/terraform-plugin-sdk/v2 v2.35.0/go.mod h1:B0Al8NyYVr8Mp/KLwssKXG1RqnTk7FySqSn4fRuLNgw=
github.com/hashicorp/terraform-plugin-testing v1.11.0 h1:MeDT5W3YHbONJt2aPQyaBsgQeAIckwPX41EUHXEn29A=
github.com/hashicorp/terraform-plugin-testing v1.11.0/go.mod h1:WNAHQ3DcgV/0J+B15WTE6hDvxcUdkPPpnB1FR3M910U=
github.com/hashicorp/terraform-registry-address v0.2.3 h1:2TAiKJ1A3MAkZlH1YI/aTVcLZRu7JseiXNRHbOAyoTI=
github.com/hashicorp/terraform-registry-address v0.2.3/go.mod h1:lFHA76T8jfQteVfT7caREqguFrW3c4MFSPhZB7HHgUM=
github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S52uzrw4x0jKQ=
@@ -319,8 +319,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 h1:ESSUROHIBHg7USnszlcdmjBEwdMj9VUvU+OPk4yl2mc=
golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@@ -343,8 +343,8 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -370,8 +370,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
@@ -382,8 +382,8 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+129 -21
View File
@@ -12,6 +12,7 @@ import (
"time"
"github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts"
"github.com/hashicorp/terraform-plugin-framework-validators/boolvalidator"
"github.com/hashicorp/terraform-plugin-framework-validators/int32validator"
"github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
"github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
@@ -50,13 +51,14 @@ type serverResource struct {
type serverModel struct {
resources.ServerModel
PublicIpv4Count types.Int32 `tfsdk:"public_ipv4_count"`
PublicIpv4Addresses types.List `tfsdk:"public_ipv4_addresses"`
PrivateIPv4Addresses types.List `tfsdk:"private_ipv4_addresses"`
Permalink types.String `tfsdk:"permalink"`
Password types.String `tfsdk:"password"`
PasswordChangeSupported types.Bool `tfsdk:"password_change_supported"`
Timeouts timeouts.Value `tfsdk:"timeouts"`
PublicIpv4Count types.Int32 `tfsdk:"public_ipv4_count"`
PublicIpv4Addresses types.List `tfsdk:"public_ipv4_addresses"`
PrivateIPv4Addresses types.List `tfsdk:"private_ipv4_addresses"`
SourceAndDestinationCheck types.Bool `tfsdk:"source_and_destination_check"`
Permalink types.String `tfsdk:"permalink"`
Password types.String `tfsdk:"password"`
PasswordChangeSupported types.Bool `tfsdk:"password_change_supported"`
Timeouts timeouts.Value `tfsdk:"timeouts"`
}
func (d *serverResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
@@ -199,6 +201,26 @@ func (r *serverResource) Schema(ctx context.Context, _ resource.SchemaRequest, r
Computed: true,
}
sourceDestCheckDescription := "This attribute can only be set if your server also has a `vpc_id` attribute set. " +
"When enabled (which is `true` by default), your server will only be able to send or receive " +
"packets that are directly addressed to one of the IP addresses associated with the Cloud Server. Generally, " +
"this is desirable behaviour because it prevents IP conflicts and other hard-to-diagnose networking faults due " +
"to incorrect network configuration. When `source_and_destination_check` is `false`, your Cloud Server will be able " +
"to send and receive packets addressed to any server. This is typically used when you want to use " +
"your Cloud Server as a VPN endpoint, a NAT server to provide internet access, or IP forwarding."
resp.Schema.Attributes["source_and_destination_check"] = &schema.BoolAttribute{
Description: sourceDestCheckDescription,
MarkdownDescription: sourceDestCheckDescription,
Optional: true,
Required: false,
Computed: true,
Validators: []validator.Bool{
boolvalidator.AlsoRequires(path.Expressions{
path.MatchRoot("vpc_id"),
}...),
},
}
privateIpv4AddressesDescription := "The private IPv4 addresses assigned to the server."
resp.Schema.Attributes["private_ipv4_addresses"] = &schema.ListAttribute{
Description: privateIpv4AddressesDescription,
@@ -248,16 +270,33 @@ func (r *serverResource) Schema(ctx context.Context, _ resource.SchemaRequest, r
}
func (r *serverResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
// Creation or destruction plan
if req.Plan.Raw.IsNull() || req.State.Raw.IsNull() {
var plan, state serverModel
if req.Plan.Raw.IsNull() {
// Destruction plan, no modification needed
return
}
// Read Terraform plan data into the model
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
if resp.Diagnostics.HasError() {
return
}
var plan, state serverModel
if plan.SourceAndDestinationCheck.IsUnknown() {
if plan.VpcId.IsNull() {
plan.SourceAndDestinationCheck = types.BoolNull()
} else {
plan.SourceAndDestinationCheck = types.BoolPointerValue(Pointer(true))
}
resp.Diagnostics.Append(resp.Plan.Set(ctx, &plan)...)
}
// Read Terraform plan data into the model
if req.State.Raw.IsNull() {
// Creation plan, no further modification needed
return
}
// Read Terraform state data into the model
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
if resp.Diagnostics.HasError() {
return
}
@@ -374,7 +413,7 @@ func (r *serverResource) Create(ctx context.Context, req resource.CreateRequest,
fmt.Sprintf("Received %s creating new server: name=%s. Details: %s", serverResp.Status(), data.Name.ValueString(), serverResp.Body))
return
}
err = r.waitForServerAction(ctx, *serverResp.JSON200.Server.Id, createActionId, "create")
err = r.waitForServerAction(ctx, *serverResp.JSON200.Server.Id, createActionId)
if err != nil {
resp.Diagnostics.AddError("Error waiting for server to be created", err.Error())
}
@@ -389,6 +428,9 @@ func (r *serverResource) Create(ctx context.Context, req resource.CreateRequest,
data.VpcId = types.Int64PointerValue(serverResp.JSON200.Server.VpcId)
data.Permalink = types.StringValue(*serverResp.JSON200.Server.Permalink)
data.PasswordChangeSupported = types.BoolValue(*serverResp.JSON200.Server.PasswordChangeSupported)
plannedSourceDestCheck := data.SourceAndDestinationCheck
serverRespSourceDestCheck := types.BoolPointerValue(serverResp.JSON200.Server.Networks.SourceAndDestinationCheck)
data.SourceAndDestinationCheck = serverRespSourceDestCheck
publicIpv4Addresses := []string{}
privateIpv4Addresses := []string{}
@@ -406,6 +448,19 @@ func (r *serverResource) Create(ctx context.Context, req resource.CreateRequest,
// Save data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
// Update source_and_destination_check if needed
if plannedSourceDestCheck.Equal(types.BoolPointerValue(Pointer(false))) {
err := r.updateSourceDestCheck(ctx, data.Id.ValueInt64(), false)
if err != nil {
resp.Diagnostics.AddError("Error updating source and destination check", err.Error())
return
}
data.SourceAndDestinationCheck = plannedSourceDestCheck
}
// Save data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}
func (r *serverResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
@@ -447,6 +502,7 @@ func (r *serverResource) Read(ctx context.Context, req resource.ReadRequest, res
data.VpcId = types.Int64PointerValue(serverResp.JSON200.Server.VpcId)
data.Permalink = types.StringValue(*serverResp.JSON200.Server.Permalink)
data.PasswordChangeSupported = types.BoolValue(*serverResp.JSON200.Server.PasswordChangeSupported)
data.SourceAndDestinationCheck = types.BoolPointerValue(serverResp.JSON200.Server.Networks.SourceAndDestinationCheck)
publicIpv4Addresses := []string{}
privateIpv4Addresses := []string{}
@@ -598,7 +654,7 @@ func (r *serverResource) Update(ctx context.Context, req resource.UpdateRequest,
fmt.Sprintf("Received %s resizing server: server_id=%s. Details: %s", resizeResp.Status(), state.Id.String(), resizeResp.Body))
return
}
err = r.waitForServerAction(ctx, state.Id.ValueInt64(), *resizeResp.JSON200.Action.Id, "resize")
err = r.waitForServerAction(ctx, state.Id.ValueInt64(), *resizeResp.JSON200.Action.Id)
if err != nil {
resp.Diagnostics.AddError("Error waiting for server to be resized", err.Error())
return
@@ -669,7 +725,7 @@ func (r *serverResource) Update(ctx context.Context, req resource.UpdateRequest,
fmt.Sprintf("Received %s rebuilding server: server_id=%s. Details: %s", rebuildResp.Status(), state.Id.String(), rebuildResp.Body))
return
}
err = r.waitForServerAction(ctx, state.Id.ValueInt64(), *rebuildResp.JSON200.Action.Id, "rebuild")
err = r.waitForServerAction(ctx, state.Id.ValueInt64(), *rebuildResp.JSON200.Action.Id)
if err != nil {
resp.Diagnostics.AddError("Error waiting for server to be rebuilt", err.Error())
return
@@ -682,6 +738,22 @@ func (r *serverResource) Update(ctx context.Context, req resource.UpdateRequest,
// Save updated data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
}
// Check source_and_destination_check
if !plan.SourceAndDestinationCheck.Equal(state.SourceAndDestinationCheck) {
if !plan.SourceAndDestinationCheck.IsNull() {
err := r.updateSourceDestCheck(ctx, state.Id.ValueInt64(), plan.SourceAndDestinationCheck.ValueBool())
if err != nil {
resp.Diagnostics.AddError("Error updating source and destination check", err.Error())
return
}
}
state.SourceAndDestinationCheck = plan.SourceAndDestinationCheck
// Save updated data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
}
}
func (r *serverResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
@@ -765,30 +837,35 @@ func (r *serverResource) ImportState(
resp.Diagnostics.Append(diags...)
}
func (r *serverResource) waitForServerAction(ctx context.Context, serverId int64, actionId int64, actionType string) error {
func (r *serverResource) waitForServerAction(ctx context.Context, serverId int64, actionId int64) error {
var lastReadyResp *binarylane.GetServersServerIdActionsActionIdResponse
for {
select {
case <-ctx.Done():
if lastReadyResp == nil {
return fmt.Errorf("timed out waiting for server %d to %s", serverId, actionType)
return fmt.Errorf("timed out waiting for server action: server_id=%d, action_id=%d", serverId, actionId)
} else {
return fmt.Errorf("timed out waiting for server %d to %s, last response was status=%s, body: %s", serverId, actionType, lastReadyResp.Status(), lastReadyResp.Body)
return fmt.Errorf("timed out waiting for server action: server_id=%d, action_id=%d, last response was status=%s, body: %s",
serverId, actionId, lastReadyResp.Status(), lastReadyResp.Body)
}
default:
readyResp, err := r.bc.client.GetServersServerIdActionsActionIdWithResponse(ctx, serverId, actionId)
if err != nil {
return fmt.Errorf("unexpected error waiting for server %d to %s: %w", serverId, actionType, err)
return fmt.Errorf("unexpected error waiting for server action: server_id=%d, action_id=%d, error: %w", serverId, actionId, err)
}
if readyResp.StatusCode() == http.StatusOK && *readyResp.JSON200.Action.Status == binarylane.Errored {
return fmt.Errorf("server %d failed to %s with error: %s", serverId, actionType, *readyResp.JSON200.Action.ResultData)
return fmt.Errorf("server action failed to with error: server_id=%d, action_id=%d, error: %s", serverId, actionId, *readyResp.JSON200.Action.ResultData)
}
if readyResp.StatusCode() == http.StatusOK && readyResp.JSON200.Action.CompletedAt != nil {
return nil
}
lastReadyResp = readyResp
tflog.Debug(ctx, fmt.Sprintf("waiting for server %d to %s: last response was status=%s, details: %s", serverId, actionType, readyResp.Status(), readyResp.Body))
tflog.Debug(ctx,
fmt.Sprintf("waiting for server action for server_id=%d, action_id=%d: last response was status=%s, details: %s",
serverId, actionId, readyResp.Status(), readyResp.Body,
),
)
}
time.Sleep(time.Second * 5)
}
@@ -809,3 +886,34 @@ func attrsRequiringRebuild(plan *serverModel, state *serverModel) []string {
return attrs
}
func (r *serverResource) updateSourceDestCheck(
ctx context.Context,
serverId int64,
sourceDestCheckEnabled bool,
) error {
tflog.Info(ctx, fmt.Sprintf("Changing source and destination check for server: server_id=%d, enabled=%t",
serverId, sourceDestCheckEnabled))
sourceDestCheckResp, err := r.bc.client.PostServersServerIdActionsChangeSourceAndDestinationCheckWithResponse(
ctx,
serverId,
binarylane.PostServersServerIdActionsChangeSourceAndDestinationCheckJSONRequestBody{
Type: "change_source_and_destination_check",
Enabled: sourceDestCheckEnabled,
},
)
if err != nil {
return fmt.Errorf("error changing source and destination check for server: server_id=%d, error: %w", serverId, err)
}
if sourceDestCheckResp.StatusCode() != http.StatusOK {
return fmt.Errorf("unexpected HTTP status code changing source and destination check for server: server_id=%d, details: %s", serverId, sourceDestCheckResp.Body)
}
err = r.waitForServerAction(ctx, serverId, *sourceDestCheckResp.JSON200.Action.Id)
if err != nil {
return fmt.Errorf("error changing source and destination check: %w", err)
}
return nil
}
@@ -60,6 +60,7 @@ resource "binarylane_server" "test" {
vpc_id = binarylane_vpc.test.id
public_ipv4_count = 1
ssh_keys = [binarylane_ssh_key.initial.id]
source_and_destination_check = false
user_data = <<EOT
#cloud-config
echo "Hello World" > /var/tmp/output.txt
@@ -91,6 +92,7 @@ echo "Hello World" > /var/tmp/output.txt
resource.TestCheckResourceAttr("binarylane_server.test", "ssh_keys.#", "1"),
resource.TestCheckResourceAttrPair("binarylane_server.test", "ssh_keys.0", "binarylane_ssh_key.initial", "id"),
resource.TestCheckResourceAttrSet("binarylane_server.test", "permalink"),
resource.TestCheckResourceAttr("binarylane_server.test", "source_and_destination_check", "false"),
// Verify data source values
resource.TestCheckResourceAttrPair("data.binarylane_server.test", "id", "binarylane_server.test", "id"),
@@ -148,6 +150,7 @@ resource "binarylane_server" "test" {
vpc_id = binarylane_vpc.test.id
public_ipv4_count = 0
ssh_keys = [binarylane_ssh_key.updated.id]
# source_and_destination_check = true # defaults to true
user_data = <<EOT
#cloud-config
echo "Hello Whitespace" > /var/tmp/output.txt
@@ -164,6 +167,7 @@ EOT
resource.TestCheckResourceAttr("binarylane_server.test", "image", "debian-12"),
resource.TestCheckResourceAttr("binarylane_server.test", "ssh_keys.#", "1"),
resource.TestCheckResourceAttrPair("binarylane_server.test", "ssh_keys.0", "binarylane_ssh_key.updated", "id"),
resource.TestCheckResourceAttr("binarylane_server.test", "source_and_destination_check", "true"),
resource.TestCheckResourceAttr("binarylane_server.test", "user_data", // test extra whitespace
`#cloud-config
echo "Hello Whitespace" > /var/tmp/output.txt
+4
View File
@@ -177,3 +177,7 @@ func listContainsUnknown(ctx context.Context, list types.List) bool {
return false
}
func Pointer[T any](d T) *T {
return &d
}