mirror of
https://github.com/oscarhermoso/terraform-provider-binarylane
synced 2026-10-19 21:49:15 +11:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 725fa71248 | |||
| 6970691546 | |||
| d8ca224107 | |||
| d168435ed6 | |||
| 85f65c9391 | |||
| 262bf0a571 |
@@ -57,6 +57,7 @@ jq '[ .regions[] | .slug ] | sort' tmp/regions.json
|
||||
|
||||
```json
|
||||
[
|
||||
"adl",
|
||||
"bne",
|
||||
"mel",
|
||||
"per",
|
||||
@@ -80,21 +81,24 @@ jq '[ .images[] | .slug ] | sort' tmp/images.json
|
||||
|
||||
```json
|
||||
[
|
||||
"alma-10",
|
||||
"alma-8",
|
||||
"alma-9",
|
||||
"byo-os",
|
||||
"byo-os-uefi",
|
||||
"byo-os-virtio-disabled",
|
||||
"cpanel-plus-whm",
|
||||
"debian-11",
|
||||
"debian-12",
|
||||
"rocky-8",
|
||||
"debian-13",
|
||||
"rocky-10",
|
||||
"rocky-9",
|
||||
"ubuntu-20.04-neon-desktop",
|
||||
"ubuntu-20.04.6",
|
||||
"ubuntu-22.04",
|
||||
"ubuntu-22.04-desktop",
|
||||
"ubuntu-24.04",
|
||||
"windows-2012-r2",
|
||||
"ubuntu-24.04-neon-desktop",
|
||||
"ubuntu-26.04",
|
||||
"windows-2016",
|
||||
"windows-2016-sql-2016-web",
|
||||
"windows-2019",
|
||||
@@ -102,7 +106,8 @@ jq '[ .images[] | .slug ] | sort' tmp/images.json
|
||||
"windows-2019-sql-2017-web",
|
||||
"windows-2022",
|
||||
"windows-2022-sql-2019-std",
|
||||
"windows-2022-sql-2019-web"
|
||||
"windows-2022-sql-2019-web",
|
||||
"windows-2025"
|
||||
]
|
||||
```
|
||||
|
||||
@@ -125,14 +130,16 @@ jq '[ .sizes[] | .slug ] | sort' tmp/sizes.json
|
||||
"cpu-4thr",
|
||||
"cpu-6thr",
|
||||
"cpu-8thr",
|
||||
"ded-3900x-1600gb",
|
||||
"ded-7900x-800gb",
|
||||
"ded-e2136-400gb",
|
||||
"ded-e2136-800gb",
|
||||
"ded-e2288g-400gb",
|
||||
"ded-e2288g-800gb",
|
||||
"hdd-1000gb",
|
||||
"hdd-2000gb",
|
||||
"hdd-4000gb",
|
||||
"hdd-500gb",
|
||||
"hdd-6000gb",
|
||||
"hdd-8000gb",
|
||||
"std-1vcpu",
|
||||
"std-2vcpu",
|
||||
"std-4vcpu",
|
||||
|
||||
@@ -29,10 +29,11 @@ data "binarylane_server" "example" {
|
||||
|
||||
- `advanced_features` (Object) (see [below for nested schema](#nestedatt--advanced_features))
|
||||
- `backups` (Boolean) If `true` this will enable two daily backups for the server. By default, backups are disabled.
|
||||
- `disk` (Number) The total storage in GB for this server. Leave null to accept the default for the size Valid values:
|
||||
- `disk` (Number) The total storage in GB for this server. Leave null to accept the default for the size. Valid values:
|
||||
- must be a multiple of 5
|
||||
- \> 60 GB must be a multiple of 10
|
||||
- \> 200 GB must be a multiple of 100
|
||||
- `disks` (Attributes List) The disks attached to this server. Leave null to let Binary Lane manage the server's disks. If specified, every disk must be listed, including the primary: exactly one entry must have `primary = true`, and its `id` and `description` are assigned by Binary Lane. (see [below for nested schema](#nestedatt--disks))
|
||||
- `image` (String) The slug of the selected operating system, such as `debian-12`. You can fetch a full list of images from the BinaryLane API.
|
||||
- `ipv6` (Boolean) If `true` this will add a public and private IPv6 address to the server. By default, IPv6 is disabled.
|
||||
- `memory` (Number) The total memory in MB for this server. Leave null to accept the default size. Valid values:
|
||||
@@ -42,7 +43,7 @@ data "binarylane_server" "example" {
|
||||
- \> 24576 MB must be a multiple of 4096
|
||||
- `name` (String) The hostname of your server, such as vps01.yourcompany.com. If not provided, the server will be created with a random name.
|
||||
- `permalink` (String) A randomly generated two-word identifier assigned to servers in regions that support this feature
|
||||
- `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.
|
||||
- `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 verified accounts.
|
||||
- `private_ipv4_addresses` (List of String) The private IPv4 addresses assigned to the server.
|
||||
- `private_ipv6_addresses` (List of String) The private IPv6 addresses assigned to the server.
|
||||
- `public_ipv4_addresses` (List of String) The public IPv4 addresses assigned to the server.
|
||||
@@ -71,3 +72,14 @@ Read-Only:
|
||||
- `qemu_guest_agent` (Boolean)
|
||||
- `uefi_boot` (Boolean)
|
||||
- `unset_uuid` (Boolean)
|
||||
|
||||
|
||||
<a id="nestedatt--disks"></a>
|
||||
### Nested Schema for `disks`
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `description` (String) A label for this disk. Assigned by Binary Lane for the primary disk, so must be left null when `primary = true`. Changing this will destroy the disk and create a new one, losing any data on it. Disks that share a description are matched in the order they are listed.
|
||||
- `id` (Number) The ID of this disk.
|
||||
- `primary` (Boolean) If `true` this is the primary disk, which the operating system is installed on. Exactly one disk must be the primary.
|
||||
- `size_gigabytes` (Number) The size of the disk in GB. The sum across all disks cannot exceed `disk`, and any remainder is left unallocated.
|
||||
|
||||
@@ -20,6 +20,14 @@ resource "binarylane_server" "example" {
|
||||
size = "std-min" # 1 VPCU, 1 GB Memory, 20 GB NVME Storage, 1000 GB Data Transfer
|
||||
public_ipv4_count = 1
|
||||
|
||||
# To manage multiple disks, every disk must be listed, including the primary
|
||||
# disk = 40
|
||||
# disks = [
|
||||
# { primary = true, size_gigabytes = 20 },
|
||||
# { description = "data1", size_gigabytes = 10 },
|
||||
# { description = "data2", size_gigabytes = 10 },
|
||||
# ]
|
||||
|
||||
# Accepts a cloud-init script or cloud-config YAML file to configure the server
|
||||
# See more: https://cloudinit.readthedocs.io/en/latest/explanation/format.html#user-data-script
|
||||
user_data = file("./init.sh")
|
||||
@@ -40,10 +48,11 @@ resource "binarylane_server" "example" {
|
||||
|
||||
- `advanced_features` (Attributes) (see [below for nested schema](#nestedatt--advanced_features))
|
||||
- `backups` (Boolean) If `true` this will enable two daily backups for the server. By default, backups are disabled.
|
||||
- `disk` (Number) The total storage in GB for this server. Leave null to accept the default for the size Valid values:
|
||||
- `disk` (Number) The total storage in GB for this server. Leave null to accept the default for the size. Valid values:
|
||||
- must be a multiple of 5
|
||||
- \> 60 GB must be a multiple of 10
|
||||
- \> 200 GB must be a multiple of 100
|
||||
- `disks` (Attributes List) The disks attached to this server. Leave null to let Binary Lane manage the server's disks. If specified, every disk must be listed, including the primary: exactly one entry must have `primary = true`, and its `id` and `description` are assigned by Binary Lane. (see [below for nested schema](#nestedatt--disks))
|
||||
- `ipv6` (Boolean) If `true` this will add a public and private IPv6 address to the server. By default, IPv6 is disabled.
|
||||
- `memory` (Number) The total memory in MB for this server. Leave null to accept the default size. Valid values:
|
||||
- must be a multiple of 128
|
||||
@@ -52,7 +61,7 @@ resource "binarylane_server" "example" {
|
||||
- \> 24576 MB must be a multiple of 4096
|
||||
- `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.
|
||||
- `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 verified accounts.
|
||||
- `separate_private_network_interface` (Boolean) This attribute can only be set if your server also has a `vpc_id` attribute set. When enabled, a separate private network interface is provided for the server's VPC traffic.
|
||||
- `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.
|
||||
@@ -91,6 +100,23 @@ Read-Only:
|
||||
- `uefi_boot` (Boolean) When this option is enabled the Cloud Server will use UEFI instead of legacy PC BIOS.
|
||||
|
||||
|
||||
<a id="nestedatt--disks"></a>
|
||||
### Nested Schema for `disks`
|
||||
|
||||
Required:
|
||||
|
||||
- `size_gigabytes` (Number) The size of the disk in GB. The sum across all disks cannot exceed `disk`, and any remainder is left unallocated.
|
||||
|
||||
Optional:
|
||||
|
||||
- `description` (String) A label for this disk. Assigned by Binary Lane for the primary disk, so must be left null when `primary = true`. Changing this will destroy the disk and create a new one, losing any data on it. Disks that share a description are matched in the order they are listed.
|
||||
- `primary` (Boolean) If `true` this is the primary disk, which the operating system is installed on. Exactly one disk must be the primary.
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `id` (Number) The ID of this disk.
|
||||
|
||||
|
||||
<a id="nestedatt--timeouts"></a>
|
||||
### Nested Schema for `timeouts`
|
||||
|
||||
|
||||
@@ -5,6 +5,14 @@ resource "binarylane_server" "example" {
|
||||
size = "std-min" # 1 VPCU, 1 GB Memory, 20 GB NVME Storage, 1000 GB Data Transfer
|
||||
public_ipv4_count = 1
|
||||
|
||||
# To manage multiple disks, every disk must be listed, including the primary
|
||||
# disk = 40
|
||||
# disks = [
|
||||
# { primary = true, size_gigabytes = 20 },
|
||||
# { description = "data1", size_gigabytes = 10 },
|
||||
# { description = "data2", size_gigabytes = 10 },
|
||||
# ]
|
||||
|
||||
# Accepts a cloud-init script or cloud-config YAML file to configure the server
|
||||
# See more: https://cloudinit.readthedocs.io/en/latest/explanation/format.html#user-data-script
|
||||
user_data = file("./init.sh")
|
||||
|
||||
@@ -1,22 +1,20 @@
|
||||
module terraform-provider-binarylane
|
||||
|
||||
go 1.24.0
|
||||
|
||||
toolchain go1.24.1
|
||||
go 1.25.8
|
||||
|
||||
require (
|
||||
github.com/deepmap/oapi-codegen v1.16.3
|
||||
github.com/hashicorp/terraform-plugin-codegen-framework v0.4.1
|
||||
github.com/hashicorp/terraform-plugin-codegen-openapi v0.3.0
|
||||
github.com/hashicorp/terraform-plugin-docs v0.24.0
|
||||
github.com/hashicorp/terraform-plugin-framework v1.18.0
|
||||
github.com/hashicorp/terraform-plugin-framework v1.19.0
|
||||
github.com/hashicorp/terraform-plugin-framework-timeouts v0.7.0
|
||||
github.com/hashicorp/terraform-plugin-framework-validators v0.19.0
|
||||
github.com/hashicorp/terraform-plugin-go v0.30.0
|
||||
github.com/hashicorp/terraform-plugin-log v0.10.0
|
||||
github.com/hashicorp/terraform-plugin-testing v1.14.0
|
||||
github.com/hashicorp/terraform-plugin-go v0.31.0
|
||||
github.com/hashicorp/terraform-plugin-log v0.11.0
|
||||
github.com/hashicorp/terraform-plugin-testing v1.16.0
|
||||
github.com/oapi-codegen/oapi-codegen/v2 v2.6.0
|
||||
github.com/oapi-codegen/runtime v1.2.0
|
||||
github.com/oapi-codegen/runtime v1.6.0
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -25,8 +23,8 @@ require (
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.2.1 // indirect
|
||||
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.1.6 // indirect
|
||||
github.com/agext/levenshtein v1.2.2 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.4.1 // indirect
|
||||
github.com/agext/levenshtein v1.2.3 // indirect
|
||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
|
||||
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
|
||||
github.com/armon/go-radix v1.0.0 // indirect
|
||||
@@ -36,7 +34,7 @@ require (
|
||||
github.com/buger/jsonparser v1.1.1 // indirect
|
||||
github.com/cloudflare/circl v1.6.3 // indirect
|
||||
github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect
|
||||
github.com/fatih/color v1.18.0 // indirect
|
||||
github.com/fatih/color v1.19.0 // indirect
|
||||
github.com/frankban/quicktest v1.14.6 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
||||
github.com/getkin/kin-openapi v0.133.0 // indirect
|
||||
@@ -52,26 +50,26 @@ require (
|
||||
github.com/hashicorp/go-cty v1.5.0 // indirect
|
||||
github.com/hashicorp/go-hclog v1.6.3 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-plugin v1.7.0 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
|
||||
github.com/hashicorp/go-plugin v1.8.0 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.8 // indirect
|
||||
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.2 // indirect
|
||||
github.com/hashicorp/go-version v1.9.0 // indirect
|
||||
github.com/hashicorp/hc-install v0.9.4 // indirect
|
||||
github.com/hashicorp/hcl/v2 v2.24.0 // indirect
|
||||
github.com/hashicorp/logutils v1.0.0 // indirect
|
||||
github.com/hashicorp/terraform-exec v0.24.0 // indirect
|
||||
github.com/hashicorp/terraform-exec v0.25.1 // indirect
|
||||
github.com/hashicorp/terraform-json v0.27.2 // indirect
|
||||
github.com/hashicorp/terraform-plugin-codegen-spec v0.2.0 // indirect
|
||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.38.1 // indirect
|
||||
github.com/hashicorp/terraform-registry-address v0.4.0 // indirect
|
||||
github.com/hashicorp/terraform-svchost v0.1.1 // indirect
|
||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.40.1 // indirect
|
||||
github.com/hashicorp/terraform-registry-address v0.5.0 // indirect
|
||||
github.com/hashicorp/terraform-svchost v0.2.1 // indirect
|
||||
github.com/hashicorp/yamux v0.1.2 // indirect
|
||||
github.com/huandu/xstrings v1.4.0 // indirect
|
||||
github.com/imdario/mergo v0.3.16 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-colorable v0.1.15 // indirect
|
||||
github.com/mattn/go-isatty v0.0.24 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
|
||||
@@ -102,19 +100,19 @@ require (
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
github.com/yuin/goldmark v1.7.7 // indirect
|
||||
github.com/yuin/goldmark-meta v1.1.0 // indirect
|
||||
github.com/zclconf/go-cty v1.17.0 // indirect
|
||||
github.com/zclconf/go-cty v1.18.1 // indirect
|
||||
go.abhg.dev/goldmark/frontmatter v0.2.0 // indirect
|
||||
golang.org/x/crypto v0.46.0 // indirect
|
||||
golang.org/x/crypto v0.54.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 // indirect
|
||||
golang.org/x/mod v0.30.0 // indirect
|
||||
golang.org/x/net v0.48.0 // indirect
|
||||
golang.org/x/sync v0.19.0 // indirect
|
||||
golang.org/x/sys v0.39.0 // indirect
|
||||
golang.org/x/text v0.32.0 // indirect
|
||||
golang.org/x/tools v0.39.0 // indirect
|
||||
golang.org/x/mod v0.37.0 // indirect
|
||||
golang.org/x/net v0.57.0 // indirect
|
||||
golang.org/x/sync v0.22.0 // indirect
|
||||
golang.org/x/sys v0.47.0 // indirect
|
||||
golang.org/x/text v0.40.0 // indirect
|
||||
golang.org/x/tools v0.47.0 // indirect
|
||||
google.golang.org/appengine v1.6.8 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect
|
||||
google.golang.org/grpc v1.79.1 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260729162451-8efbd57d26e0 // indirect
|
||||
google.golang.org/grpc v1.83.0 // indirect
|
||||
google.golang.org/protobuf v1.36.11 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
||||
@@ -13,11 +13,11 @@ github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj
|
||||
github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
|
||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw=
|
||||
github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
||||
github.com/ProtonMail/go-crypto v1.4.1 h1:9RfcZHqEQUvP8RzecWEUafnZVtEvrBVL9BiF67IQOfM=
|
||||
github.com/ProtonMail/go-crypto v1.4.1/go.mod h1:e1OaTyu5SYVrO9gKOEhTc+5UcXtTUa+P3uLudwcgPqo=
|
||||
github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
|
||||
github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE=
|
||||
github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
|
||||
github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=
|
||||
github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
|
||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
|
||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
|
||||
github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec=
|
||||
@@ -58,8 +58,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql
|
||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
||||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||
github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w=
|
||||
github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
@@ -70,10 +70,10 @@ github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz
|
||||
github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
||||
github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM=
|
||||
github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
|
||||
github.com/go-git/go-git/v5 v5.14.0 h1:/MD3lCrGjCen5WfEAzKg00MJJffKhC8gzS80ycmCi60=
|
||||
github.com/go-git/go-git/v5 v5.14.0/go.mod h1:Z5Xhoia5PcWA3NF8vRLURn9E5FRhSl7dGj9ItW3Wk5k=
|
||||
github.com/go-git/go-billy/v5 v5.8.0 h1:I8hjc3LbBlXTtVuFNJuwYuMiHvQJDq1AT6u4DwDzZG0=
|
||||
github.com/go-git/go-billy/v5 v5.8.0/go.mod h1:RpvI/rw4Vr5QA+Z60c6d6LXH0rYJo0uD5SqfmrrheCY=
|
||||
github.com/go-git/go-git/v5 v5.18.0 h1:O831KI+0PR51hM2kep6T8k+w0/LIAD490gvqMCvL5hM=
|
||||
github.com/go-git/go-git/v5 v5.18.0/go.mod h1:pW/VmeqkanRFqR6AljLcs7EA7FbZaN5MQqO7oZADXpo=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
@@ -127,23 +127,23 @@ github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVH
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/hashicorp/go-plugin v1.7.0 h1:YghfQH/0QmPNc/AZMTFE3ac8fipZyZECHdDPshfk+mA=
|
||||
github.com/hashicorp/go-plugin v1.7.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
|
||||
github.com/hashicorp/go-plugin v1.8.0 h1:ie8S6RRY8RvB2usYZv+AAZ/wBvx2AU5p5QeP5j/FORs=
|
||||
github.com/hashicorp/go-plugin v1.8.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.8 h1:ylXZWnqa7Lhqpk0L1P1LzDtGcCR0rPVUrx/c8Unxc48=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
||||
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
|
||||
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/hc-install v0.9.2 h1:v80EtNX4fCVHqzL9Lg/2xkp62bbvQMnvPQ0G+OmtO24=
|
||||
github.com/hashicorp/hc-install v0.9.2/go.mod h1:XUqBQNnuT4RsxoxiM9ZaUk0NX8hi2h+Lb6/c0OZnC/I=
|
||||
github.com/hashicorp/go-version v1.9.0 h1:CeOIz6k+LoN3qX9Z0tyQrPtiB1DFYRPfCIBtaXPSCnA=
|
||||
github.com/hashicorp/go-version v1.9.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/hc-install v0.9.4 h1:KKWOpUG0EqIV63Qk2GGFrZ0s275NVs5lKf9N5vjBNoc=
|
||||
github.com/hashicorp/hc-install v0.9.4/go.mod h1:4LRYeEN2bMIFfIv57ldMWt9awfuZhvpbRt0vWmv51WU=
|
||||
github.com/hashicorp/hcl/v2 v2.24.0 h1:2QJdZ454DSsYGoaE6QheQZjtKZSUs9Nh2izTWiwQxvE=
|
||||
github.com/hashicorp/hcl/v2 v2.24.0/go.mod h1:oGoO1FIQYfn/AgyOhlg9qLC6/nOJPX3qGbkZpYAcqfM=
|
||||
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.24.0 h1:mL0xlk9H5g2bn0pPF6JQZk5YlByqSqrO5VoaNtAf8OE=
|
||||
github.com/hashicorp/terraform-exec v0.24.0/go.mod h1:lluc/rDYfAhYdslLJQg3J0oDqo88oGQAdHR+wDqFvo4=
|
||||
github.com/hashicorp/terraform-exec v0.25.1 h1:PRutYRGM8pixV3B8812NYoBK5O+yuf3qcB/70KFKGiU=
|
||||
github.com/hashicorp/terraform-exec v0.25.1/go.mod h1:+izOYrs9sKMQK4OYvGDnrSSJHY/pm4e4eXFqSL2Q5mA=
|
||||
github.com/hashicorp/terraform-json v0.27.2 h1:BwGuzM6iUPqf9JYM/Z4AF1OJ5VVJEEzoKST/tRDBJKU=
|
||||
github.com/hashicorp/terraform-json v0.27.2/go.mod h1:GzPLJ1PLdUG5xL6xn1OXWIjteQRT2CNT9o/6A9mi9hE=
|
||||
github.com/hashicorp/terraform-plugin-codegen-framework v0.4.1 h1:eaI/3dsu2T5QAXbA+7N+B+UBj20GdtYnsRuYypKh3S4=
|
||||
@@ -154,24 +154,24 @@ github.com/hashicorp/terraform-plugin-codegen-spec v0.2.0 h1:91dQG1A/DxP6vRz9Giy
|
||||
github.com/hashicorp/terraform-plugin-codegen-spec v0.2.0/go.mod h1:fywrEKpordQypmAjz/HIfm2LuNVmyJ6KDe8XT9GdJxQ=
|
||||
github.com/hashicorp/terraform-plugin-docs v0.24.0 h1:YNZYd+8cpYclQyXbl1EEngbld8w7/LPOm99GD5nikIU=
|
||||
github.com/hashicorp/terraform-plugin-docs v0.24.0/go.mod h1:YLg+7LEwVmRuJc0EuCw0SPLxuQXw5mW8iJ5ml/kvi+o=
|
||||
github.com/hashicorp/terraform-plugin-framework v1.18.0 h1:Xy6OfqSTZfAAKXSlJ810lYvuQvYkOpSUoNMQ9l2L1RA=
|
||||
github.com/hashicorp/terraform-plugin-framework v1.18.0/go.mod h1:eeFIf68PME+kenJeqSrIcpHhYQK0TOyv7ocKdN4Z35E=
|
||||
github.com/hashicorp/terraform-plugin-framework v1.19.0 h1:q0bwyhxAOR3vfdgbk9iplv3MlTv/dhBHTXjQOtQDoBA=
|
||||
github.com/hashicorp/terraform-plugin-framework v1.19.0/go.mod h1:YRXOBu0jvs7xp4AThBbX4mAzYaMJ1JgtFH//oGKxwLc=
|
||||
github.com/hashicorp/terraform-plugin-framework-timeouts v0.7.0 h1:jblRy1PkLfPm5hb5XeMa3tezusnMRziUGqtT5epSYoI=
|
||||
github.com/hashicorp/terraform-plugin-framework-timeouts v0.7.0/go.mod h1:5jm2XK8uqrdiSRfD5O47OoxyGMCnwTcl8eoiDgSa+tc=
|
||||
github.com/hashicorp/terraform-plugin-framework-validators v0.19.0 h1:Zz3iGgzxe/1XBkooZCewS0nJAaCFPFPHdNJd8FgE4Ow=
|
||||
github.com/hashicorp/terraform-plugin-framework-validators v0.19.0/go.mod h1:GBKTNGbGVJohU03dZ7U8wHqc2zYnMUawgCN+gC0itLc=
|
||||
github.com/hashicorp/terraform-plugin-go v0.30.0 h1:VmEiD0n/ewxbvV5VI/bYwNtlSEAXtHaZlSnyUUuQK6k=
|
||||
github.com/hashicorp/terraform-plugin-go v0.30.0/go.mod h1:8d523ORAW8OHgA9e8JKg0ezL3XUO84H0A25o4NY/jRo=
|
||||
github.com/hashicorp/terraform-plugin-log v0.10.0 h1:eu2kW6/QBVdN4P3Ju2WiB2W3ObjkAsyfBsL3Wh1fj3g=
|
||||
github.com/hashicorp/terraform-plugin-log v0.10.0/go.mod h1:/9RR5Cv2aAbrqcTSdNmY1NRHP4E3ekrXRGjqORpXyB0=
|
||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.38.1 h1:mlAq/OrMlg04IuJT7NpefI1wwtdpWudnEmjuQs04t/4=
|
||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.38.1/go.mod h1:GQhpKVvvuwzD79e8/NZ+xzj+ZpWovdPAe8nfV/skwNU=
|
||||
github.com/hashicorp/terraform-plugin-testing v1.14.0 h1:5t4VKrjOJ0rg0sVuSJ86dz5K7PHsMO6OKrHFzDBerWA=
|
||||
github.com/hashicorp/terraform-plugin-testing v1.14.0/go.mod h1:1qfWkecyYe1Do2EEOK/5/WnTyvC8wQucUkkhiGLg5nk=
|
||||
github.com/hashicorp/terraform-registry-address v0.4.0 h1:S1yCGomj30Sao4l5BMPjTGZmCNzuv7/GDTDX99E9gTk=
|
||||
github.com/hashicorp/terraform-registry-address v0.4.0/go.mod h1:LRS1Ay0+mAiRkUyltGT+UHWkIqTFvigGn/LbMshfflE=
|
||||
github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S52uzrw4x0jKQ=
|
||||
github.com/hashicorp/terraform-svchost v0.1.1/go.mod h1:mNsjQfZyf/Jhz35v6/0LWcv26+X7JPS+buii2c9/ctc=
|
||||
github.com/hashicorp/terraform-plugin-go v0.31.0 h1:0Fz2r9DQ+kNNl6bx8HRxFd1TfMKUvnrOtvJPmp3Z0q8=
|
||||
github.com/hashicorp/terraform-plugin-go v0.31.0/go.mod h1:A88bDhd/cW7FnwqxQRz3slT+QY6yzbHKc6AOTtmdeS8=
|
||||
github.com/hashicorp/terraform-plugin-log v0.11.0 h1:WjhcpZIVqP8YRe83+dIZXncwSgtu4vh27i23G33PUQY=
|
||||
github.com/hashicorp/terraform-plugin-log v0.11.0/go.mod h1:XygBz8+m5kgwTb73MMyrnUjeNQeVWECEfg+h2opMsj0=
|
||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.40.1 h1:2yPUd7esMOpuTaG3y1iEla1iw+tla+3ZEkkBnmOAre4=
|
||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.40.1/go.mod h1:sq8qsxh+PwdvTQFcd17kfCoBgQo46ADNMvCpKE7t/gY=
|
||||
github.com/hashicorp/terraform-plugin-testing v1.16.0 h1:GB97nGnJ1hESpDrCjqZig38RodSF0gdRzxlDupLXP38=
|
||||
github.com/hashicorp/terraform-plugin-testing v1.16.0/go.mod h1:eQPYAy9xFMV7xtIFX8Y+wJGtUB++HBl329zCF6PBMZk=
|
||||
github.com/hashicorp/terraform-registry-address v0.5.0 h1:FAlhWOLFgMvo/4f5DPhCTwRYfHYdF1DjiOtgxfGr4p0=
|
||||
github.com/hashicorp/terraform-registry-address v0.5.0/go.mod h1:wOJYCN60i/gSQGPCcGdamatjxn65EZBMFVt7c/Suzis=
|
||||
github.com/hashicorp/terraform-svchost v0.2.1 h1:ubvrTFw3Q7CsoEaX7V06PtCTKG3wu7GyyobAoN4eF3Q=
|
||||
github.com/hashicorp/terraform-svchost v0.2.1/go.mod h1:zDMheBLvNzu7Q6o9TBvPqiZToJcSuCLXjAXxBslSky4=
|
||||
github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8=
|
||||
github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
@@ -202,12 +202,12 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||
github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY=
|
||||
github.com/mattn/go-colorable v0.1.15/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-isatty v0.0.24 h1:tGZZoVgT/KiqK1c8ocVLeDS8BSWMRd47J3Lbz7vsReI=
|
||||
github.com/mattn/go-isatty v0.0.24/go.mod h1:nMCL3Zebbrt45jsMDgnfIwz6ydEQApk5oEI3HqDio6A=
|
||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
||||
@@ -227,10 +227,12 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwd
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/oapi-codegen/nullable v1.1.0 h1:eAh8JVc5430VtYVnq00Hrbpag9PFRGWLjxR1/3KntMs=
|
||||
github.com/oapi-codegen/nullable v1.1.0/go.mod h1:KUZ3vUzkmEKY90ksAmit2+5juDIhIZhfDl+0PwOQlFY=
|
||||
github.com/oapi-codegen/oapi-codegen/v2 v2.6.0 h1:4i+F2cvwBFZeplxCssNdLy3MhNzUD87mI3HnayHZkAU=
|
||||
github.com/oapi-codegen/oapi-codegen/v2 v2.6.0/go.mod h1:eWHeJSohQJIINJZzzQriVynfGsnlQVh0UkN2UYYcw4Q=
|
||||
github.com/oapi-codegen/runtime v1.2.0 h1:RvKc1CVS1QeKSNzO97FBQbSMZyQ8s6rZd+LpmzwHMP4=
|
||||
github.com/oapi-codegen/runtime v1.2.0/go.mod h1:Y7ZhmmlE8ikZOmuHRRndiIm7nf3xcVv+YMweKgG1DT0=
|
||||
github.com/oapi-codegen/runtime v1.6.0 h1:7Xx+GlueD6nRuyKoCPzL434Jfi3BetbiJOrzCHp/VPU=
|
||||
github.com/oapi-codegen/runtime v1.6.0/go.mod h1:GwV7hC2hviaMzj+ITfHVRESK5J2W/GefVwIND/bMGvU=
|
||||
github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY=
|
||||
github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw=
|
||||
github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c=
|
||||
@@ -321,37 +323,37 @@ github.com/yuin/goldmark v1.7.7 h1:5m9rrB1sW3JUMToKFQfb+FGt1U7r57IHu5GrYrG2nqU=
|
||||
github.com/yuin/goldmark v1.7.7/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
|
||||
github.com/yuin/goldmark-meta v1.1.0 h1:pWw+JLHGZe8Rk0EGsMVssiNb/AaPMHfSRszZeUeiOUc=
|
||||
github.com/yuin/goldmark-meta v1.1.0/go.mod h1:U4spWENafuA7Zyg+Lj5RqK/MF+ovMYtBvXi1lBb2VP0=
|
||||
github.com/zclconf/go-cty v1.17.0 h1:seZvECve6XX4tmnvRzWtJNHdscMtYEx5R7bnnVyd/d0=
|
||||
github.com/zclconf/go-cty v1.17.0/go.mod h1:wqFzcImaLTI6A5HfsRwB0nj5n0MRZFwmey8YoFPPs3U=
|
||||
github.com/zclconf/go-cty v1.18.1 h1:yEGE8M4iIZlyKQURZNb2SnEyZlZHUcBCnx6KF81KuwM=
|
||||
github.com/zclconf/go-cty v1.18.1/go.mod h1:qpnV6EDNgC1sns/AleL1fvatHw72j+S+nS+MJ+T2CSg=
|
||||
github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo=
|
||||
github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM=
|
||||
go.abhg.dev/goldmark/frontmatter v0.2.0 h1:P8kPG0YkL12+aYk2yU3xHv4tcXzeVnN+gU0tJ5JnxRw=
|
||||
go.abhg.dev/goldmark/frontmatter v0.2.0/go.mod h1:XqrEkZuM57djk7zrlRUB02x8I5J0px76YjkOzhB4YlU=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
||||
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
||||
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
||||
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
||||
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
||||
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
||||
go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU=
|
||||
go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc=
|
||||
go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc=
|
||||
go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo=
|
||||
go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58=
|
||||
go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA=
|
||||
go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk=
|
||||
go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
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.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
|
||||
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
|
||||
golang.org/x/crypto v0.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw=
|
||||
golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk=
|
||||
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=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk=
|
||||
golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc=
|
||||
golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ=
|
||||
golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
@@ -362,14 +364,14 @@ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
|
||||
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
|
||||
golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE=
|
||||
golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
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.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek=
|
||||
golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
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=
|
||||
@@ -393,9 +395,8 @@ golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/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.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
|
||||
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
|
||||
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
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=
|
||||
@@ -405,27 +406,27 @@ 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.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
|
||||
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
|
||||
golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs=
|
||||
golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY=
|
||||
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=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
|
||||
golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
|
||||
golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q=
|
||||
golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
|
||||
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
|
||||
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
|
||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260729162451-8efbd57d26e0 h1:mJiOtnGp0k/BcSgdu03G2NwnscCfCH+h2QKUBZr18KI=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260729162451-8efbd57d26e0/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||
google.golang.org/grpc v1.83.0 h1:JeNZEKJFbQxArAMl+hiytHauacDNqJUllNfmIMmpqnQ=
|
||||
google.golang.org/grpc v1.83.0/go.mod h1:kDyl6SKsiHKt0uylY5gtn5cEjkrIOhQOGDgIc4JGwzQ=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
|
||||
@@ -4106,6 +4106,22 @@ func NewGetLoadBalancersRequest(server string, params *GetLoadBalancersParams) (
|
||||
if params != nil {
|
||||
queryValues := queryURL.Query()
|
||||
|
||||
if params.Name != nil {
|
||||
|
||||
if queryFrag, err := runtime.StyleParamWithOptions("form", true, "name", *params.Name, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "string", Format: ""}); err != nil {
|
||||
return nil, err
|
||||
} else if parsed, err := url.ParseQuery(queryFrag); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
for k, v := range parsed {
|
||||
for _, v2 := range v {
|
||||
queryValues.Add(k, v2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if params.Page != nil {
|
||||
|
||||
if queryFrag, err := runtime.StyleParamWithOptions("form", true, "page", *params.Page, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "integer", Format: "int32"}); err != nil {
|
||||
|
||||
@@ -1059,13 +1059,14 @@ func (e TaxCodeType) Valid() bool {
|
||||
|
||||
// Defines values for ThresholdAlertType.
|
||||
const (
|
||||
Cpu ThresholdAlertType = "cpu"
|
||||
DataTransferUsed ThresholdAlertType = "data-transfer-used"
|
||||
MemoryUsed ThresholdAlertType = "memory-used"
|
||||
NetworkIncoming ThresholdAlertType = "network-incoming"
|
||||
NetworkOutgoing ThresholdAlertType = "network-outgoing"
|
||||
StorageRequests ThresholdAlertType = "storage-requests"
|
||||
StorageUsed ThresholdAlertType = "storage-used"
|
||||
Cpu ThresholdAlertType = "cpu"
|
||||
DataTransferUsed ThresholdAlertType = "data-transfer-used"
|
||||
LockedBackupSlots ThresholdAlertType = "locked-backup-slots"
|
||||
MemoryUsed ThresholdAlertType = "memory-used"
|
||||
NetworkIncoming ThresholdAlertType = "network-incoming"
|
||||
NetworkOutgoing ThresholdAlertType = "network-outgoing"
|
||||
StorageRequests ThresholdAlertType = "storage-requests"
|
||||
StorageUsed ThresholdAlertType = "storage-used"
|
||||
)
|
||||
|
||||
// Valid indicates whether the value is a known member of the ThresholdAlertType enum.
|
||||
@@ -1075,6 +1076,8 @@ func (e ThresholdAlertType) Valid() bool {
|
||||
return true
|
||||
case DataTransferUsed:
|
||||
return true
|
||||
case LockedBackupSlots:
|
||||
return true
|
||||
case MemoryUsed:
|
||||
return true
|
||||
case NetworkIncoming:
|
||||
@@ -1164,14 +1167,15 @@ func (e VideoDevice) Valid() bool {
|
||||
|
||||
// Defines values for VmMachineType.
|
||||
const (
|
||||
PcI440fx1point5 VmMachineType = "pc_i440fx_1point5"
|
||||
PcI440fx2point11 VmMachineType = "pc_i440fx_2point11"
|
||||
PcI440fx4point1 VmMachineType = "pc_i440fx_4point1"
|
||||
PcI440fx4point2 VmMachineType = "pc_i440fx_4point2"
|
||||
PcI440fx5point0 VmMachineType = "pc_i440fx_5point0"
|
||||
PcI440fx5point1 VmMachineType = "pc_i440fx_5point1"
|
||||
PcI440fx7point2 VmMachineType = "pc_i440fx_7point2"
|
||||
PcI440fx8point2 VmMachineType = "pc_i440fx_8point2"
|
||||
PcI440fx1point5 VmMachineType = "pc_i440fx_1point5"
|
||||
PcI440fx2point11 VmMachineType = "pc_i440fx_2point11"
|
||||
PcI440fx4point1 VmMachineType = "pc_i440fx_4point1"
|
||||
PcI440fx4point2 VmMachineType = "pc_i440fx_4point2"
|
||||
PcI440fx5point0 VmMachineType = "pc_i440fx_5point0"
|
||||
PcI440fx5point1 VmMachineType = "pc_i440fx_5point1"
|
||||
PcI440fx7point2 VmMachineType = "pc_i440fx_7point2"
|
||||
PcI440fx7point2point1 VmMachineType = "pc_i440fx_7point2point1"
|
||||
PcI440fx8point2 VmMachineType = "pc_i440fx_8point2"
|
||||
)
|
||||
|
||||
// Valid indicates whether the value is a known member of the VmMachineType enum.
|
||||
@@ -1191,6 +1195,8 @@ func (e VmMachineType) Valid() bool {
|
||||
return true
|
||||
case PcI440fx7point2:
|
||||
return true
|
||||
case PcI440fx7point2point1:
|
||||
return true
|
||||
case PcI440fx8point2:
|
||||
return true
|
||||
default:
|
||||
@@ -1209,7 +1215,7 @@ type Account struct {
|
||||
// Email The email address registered for this account.
|
||||
Email string `json:"email"`
|
||||
|
||||
// EmailVerified Whether this account has been verified. Un-verified accounts are subject to some restrictions.
|
||||
// EmailVerified Whether this account has been verified. Unverified accounts are subject to some restrictions.
|
||||
EmailVerified bool `json:"email_verified"`
|
||||
|
||||
// Status The status of this account.
|
||||
@@ -1471,6 +1477,7 @@ type AdvancedServerFeatures struct {
|
||||
// | pc_i440fx_5point0 | PC i440FX 5.0 |
|
||||
// | pc_i440fx_5point1 | PC i440FX 5.1 |
|
||||
// | pc_i440fx_7point2 | PC i440FX 7.2 |
|
||||
// | pc_i440fx_7point2point1 | PC i440FX 7.2.1 |
|
||||
// | pc_i440fx_8point2 | PC i440FX 8.2 |
|
||||
//
|
||||
MachineType *VmMachineType `json:"machine_type,omitempty"`
|
||||
@@ -1662,6 +1669,7 @@ type ChangeAdvancedFeatures struct {
|
||||
// | pc_i440fx_5point0 | PC i440FX 5.0 |
|
||||
// | pc_i440fx_5point1 | PC i440FX 5.1 |
|
||||
// | pc_i440fx_7point2 | PC i440FX 7.2 |
|
||||
// | pc_i440fx_7point2point1 | PC i440FX 7.2.1 |
|
||||
// | pc_i440fx_8point2 | PC i440FX 8.2 |
|
||||
//
|
||||
MachineType *VmMachineType `json:"machine_type,omitempty"`
|
||||
@@ -2027,12 +2035,15 @@ type CreateServerRequest struct {
|
||||
// Password If this is provided the default remote user account's password will be set to this value. If this is null a random password will be generated and emailed to the account email address.
|
||||
Password *string `json:"password,omitempty"`
|
||||
|
||||
// PortBlocking 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.
|
||||
// PortBlocking 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 verified accounts.
|
||||
PortBlocking *bool `json:"port_blocking,omitempty"`
|
||||
|
||||
// Region The slug of the selected region.
|
||||
Region string `json:"region"`
|
||||
|
||||
// SeparatePrivateNetworkInterface If true this will enable a separate private network interface for the server. This is only available for servers in a VPC.
|
||||
SeparatePrivateNetworkInterface *bool `json:"separate_private_network_interface,omitempty"`
|
||||
|
||||
// Size The slug of the selected size.
|
||||
Size string `json:"size"`
|
||||
|
||||
@@ -2153,16 +2164,16 @@ type DisableSelinuxType string
|
||||
// Disk defines model for Disk.
|
||||
type Disk struct {
|
||||
// Description A description of this disk.
|
||||
Description *string `json:"description,omitempty"`
|
||||
Description *string `json:"description,omitempty" tfsdk:"description"`
|
||||
|
||||
// Id The ID of this disk.
|
||||
Id int64 `json:"id"`
|
||||
Id int64 `json:"id" tfsdk:"id"`
|
||||
|
||||
// Primary A primary disk is treated differently from other disks.
|
||||
Primary bool `json:"primary"`
|
||||
Primary bool `json:"primary" tfsdk:"primary"`
|
||||
|
||||
// SizeGigabytes The size of the disk in GB.
|
||||
SizeGigabytes float64 `json:"size_gigabytes"`
|
||||
SizeGigabytes float64 `json:"size_gigabytes" tfsdk:"size_gigabytes"`
|
||||
}
|
||||
|
||||
// DistributionFeature
|
||||
@@ -2881,6 +2892,9 @@ type Networks struct {
|
||||
// Ipv6ReverseNameservers Any configured IPv6 reverse nameservers for this server. Please see our documentation for how this interacts with IPv6 nameserver settings at the account level.
|
||||
Ipv6ReverseNameservers *[]string `json:"ipv6_reverse_nameservers,omitempty"`
|
||||
|
||||
// MacAddress The MAC address of this server's primary network interface. Customers may need this for ARP entries, DHCP reservations on a VPC, or MAC-based licensing.
|
||||
MacAddress string `json:"mac_address"`
|
||||
|
||||
// PortBlocking Whether the default port blocking is enabled for this server.
|
||||
PortBlocking bool `json:"port_blocking"`
|
||||
|
||||
@@ -3233,13 +3247,13 @@ type Sample struct {
|
||||
// MemoryUsageBytes The virtual memory used in bytes.
|
||||
MemoryUsageBytes float64 `json:"memory_usage_bytes"`
|
||||
|
||||
// NetworkIncomingKbps The incoming network data rate in Kb per second.
|
||||
// NetworkIncomingKbps The incoming network data rate in KB per second (binary: 1 KB = 1024 bytes).
|
||||
NetworkIncomingKbps float64 `json:"network_incoming_kbps"`
|
||||
|
||||
// NetworkOutgoingKbps The outgoing network data rate in Kb per second.
|
||||
// NetworkOutgoingKbps The outgoing network data rate in KB per second (binary: 1 KB = 1024 bytes).
|
||||
NetworkOutgoingKbps float64 `json:"network_outgoing_kbps"`
|
||||
|
||||
// StorageReadKbps The storage read rate in Kb per second.
|
||||
// StorageReadKbps The storage read rate in KB per second (binary: 1 KB = 1024 bytes).
|
||||
StorageReadKbps float64 `json:"storage_read_kbps"`
|
||||
|
||||
// StorageReadRequestsPerSecond The storage read requests per second.
|
||||
@@ -3248,7 +3262,7 @@ type Sample struct {
|
||||
// StorageUsageMegabytes The total storage used in MB.
|
||||
StorageUsageMegabytes float64 `json:"storage_usage_megabytes"`
|
||||
|
||||
// StorageWriteKbps The storage write rate in Kb per second.
|
||||
// StorageWriteKbps The storage write rate in KB per second (binary: 1 KB = 1024 bytes).
|
||||
StorageWriteKbps float64 `json:"storage_write_kbps"`
|
||||
|
||||
// StorageWriteRequestsPerSecond The storage write requests per second.
|
||||
@@ -3355,6 +3369,9 @@ type Server struct {
|
||||
// Image The base image used to create this server.
|
||||
Image Image `json:"image"`
|
||||
|
||||
// IsUnderMaintenance If true, this server is currently under maintenance and most actions will not be available. If this is null the status was not checked.
|
||||
IsUnderMaintenance *bool `json:"is_under_maintenance,omitempty"`
|
||||
|
||||
// Kernel The currently selected kernel for the server.
|
||||
Kernel *Kernel `json:"kernel,omitempty"`
|
||||
|
||||
@@ -3790,6 +3807,9 @@ type ThresholdAlert struct {
|
||||
// CurrentValue The last measured value for this alert type over the threshold alert period. Refer to the documentation for each threshold alert type for what this value measures in the context of the alert type. If there is no measured value in the threshold alert period this will be null.
|
||||
CurrentValue *int32 `json:"current_value,omitempty"`
|
||||
|
||||
// Description A human-readable description of what this threshold alert measures.
|
||||
Description string `json:"description"`
|
||||
|
||||
// Enabled If a threshold alert is not enabled it will not generate warnings for the user.
|
||||
Enabled bool `json:"enabled"`
|
||||
|
||||
@@ -3799,6 +3819,12 @@ type ThresholdAlert struct {
|
||||
// LastRaised The date and time (if any) in ISO8601 format of the last time this alert was raised. An alert may not be raised again until it has been cleared.
|
||||
LastRaised *time.Time `json:"last_raised,omitempty"`
|
||||
|
||||
// Name The display name of this threshold alert.
|
||||
Name string `json:"name"`
|
||||
|
||||
// Unit The unit suffix for this alert's value (e.g. `"%"` or `"requests/second"`).
|
||||
Unit string `json:"unit"`
|
||||
|
||||
// Value The threshold value of the alert. Refer to the documentation for each threshold alert type for what this value measures in the context of the alert type.
|
||||
Value int32 `json:"value"`
|
||||
}
|
||||
@@ -3824,6 +3850,7 @@ type ThresholdAlertRequest struct {
|
||||
// | data-transfer-used | The alert is based off the percentage of your monthly data transfer limit. |
|
||||
// | storage-used | The alert is based off the disk space consumed as a percentage of your total disk space. If the server runs out of disk space programs may fail to execute or be unable to create new files, or the server may become unresponsive. |
|
||||
// | memory-used | The alert is based off the virtual memory consumed as a percentage of your physical memory. Virtual memory includes the swap file so the percentage may exceed 100% indicating that the server has run out of physical memory and is relying on swap space, which will generally cause poor performance. |
|
||||
// | locked-backup-slots | The alert is based off the percentage of scheduled backup slots (daily, weekly, monthly) occupied by locked backups. When all slots are locked, automated backups cannot proceed. |
|
||||
type ThresholdAlertType string
|
||||
|
||||
// ThresholdAlertsResponse defines model for ThresholdAlertsResponse.
|
||||
@@ -4006,6 +4033,7 @@ type VideoDevice string
|
||||
// | pc_i440fx_5point0 | PC i440FX 5.0 |
|
||||
// | pc_i440fx_5point1 | PC i440FX 5.1 |
|
||||
// | pc_i440fx_7point2 | PC i440FX 7.2 |
|
||||
// | pc_i440fx_7point2point1 | PC i440FX 7.2.1 |
|
||||
// | pc_i440fx_8point2 | PC i440FX 8.2 |
|
||||
type VmMachineType string
|
||||
|
||||
@@ -4065,7 +4093,7 @@ type GetAccountKeysParams struct {
|
||||
// Page The selected page. Page numbering starts at 1
|
||||
Page *int32 `form:"page,omitempty" json:"page,omitempty"`
|
||||
|
||||
// PerPage The number of results to show per page.
|
||||
// PerPage The number of results to show per page. Use 0 to return only the total count.
|
||||
PerPage *int32 `form:"per_page,omitempty" json:"per_page,omitempty"`
|
||||
}
|
||||
|
||||
@@ -4080,7 +4108,7 @@ type GetActionsParams struct {
|
||||
// Page The selected page. Page numbering starts at 1
|
||||
Page *int32 `form:"page,omitempty" json:"page,omitempty"`
|
||||
|
||||
// PerPage The number of results to show per page.
|
||||
// PerPage The number of results to show per page. Use 0 to return only the total count.
|
||||
PerPage *int32 `form:"per_page,omitempty" json:"per_page,omitempty"`
|
||||
}
|
||||
|
||||
@@ -4092,7 +4120,7 @@ type GetCustomersMyInvoicesParams struct {
|
||||
// Page The selected page. Page numbering starts at 1
|
||||
Page *int32 `form:"page,omitempty" json:"page,omitempty"`
|
||||
|
||||
// PerPage The number of results to show per page.
|
||||
// PerPage The number of results to show per page. Use 0 to return only the total count.
|
||||
PerPage *int32 `form:"per_page,omitempty" json:"per_page,omitempty"`
|
||||
}
|
||||
|
||||
@@ -4101,7 +4129,7 @@ type GetDataUsagesCurrentParams struct {
|
||||
// Page The selected page. Page numbering starts at 1
|
||||
Page *int32 `form:"page,omitempty" json:"page,omitempty"`
|
||||
|
||||
// PerPage The number of results to show per page.
|
||||
// PerPage The number of results to show per page. Use 0 to return only the total count.
|
||||
PerPage *int32 `form:"per_page,omitempty" json:"per_page,omitempty"`
|
||||
}
|
||||
|
||||
@@ -4110,7 +4138,7 @@ type GetDomainsParams struct {
|
||||
// Page The selected page. Page numbering starts at 1
|
||||
Page *int32 `form:"page,omitempty" json:"page,omitempty"`
|
||||
|
||||
// PerPage The number of results to show per page.
|
||||
// PerPage The number of results to show per page. Use 0 to return only the total count.
|
||||
PerPage *int32 `form:"per_page,omitempty" json:"per_page,omitempty"`
|
||||
}
|
||||
|
||||
@@ -4155,7 +4183,7 @@ type GetDomainsDomainNameRecordsParams struct {
|
||||
// Page The selected page. Page numbering starts at 1
|
||||
Page *int32 `form:"page,omitempty" json:"page,omitempty"`
|
||||
|
||||
// PerPage The number of results to show per page.
|
||||
// PerPage The number of results to show per page. Use 0 to return only the total count.
|
||||
PerPage *int32 `form:"per_page,omitempty" json:"per_page,omitempty"`
|
||||
}
|
||||
|
||||
@@ -4206,7 +4234,7 @@ type GetImagesParams struct {
|
||||
// Page The selected page. Page numbering starts at 1
|
||||
Page *int32 `form:"page,omitempty" json:"page,omitempty"`
|
||||
|
||||
// PerPage The number of results to show per page.
|
||||
// PerPage The number of results to show per page. Use 0 to return only the total count.
|
||||
PerPage *int32 `form:"per_page,omitempty" json:"per_page,omitempty"`
|
||||
}
|
||||
|
||||
@@ -4218,10 +4246,13 @@ type GetImagesImageIdOrSlugParamsImageIdOrSlug1 = string
|
||||
|
||||
// GetLoadBalancersParams defines parameters for GetLoadBalancers.
|
||||
type GetLoadBalancersParams struct {
|
||||
// Name Providing a name restricts the results to load balancers with this name (case insensitive).
|
||||
Name *string `form:"name,omitempty" json:"name,omitempty"`
|
||||
|
||||
// Page The selected page. Page numbering starts at 1
|
||||
Page *int32 `form:"page,omitempty" json:"page,omitempty"`
|
||||
|
||||
// PerPage The number of results to show per page.
|
||||
// PerPage The number of results to show per page. Use 0 to return only the total count.
|
||||
PerPage *int32 `form:"per_page,omitempty" json:"per_page,omitempty"`
|
||||
}
|
||||
|
||||
@@ -4248,7 +4279,7 @@ type GetRegionsParams struct {
|
||||
// Page The selected page. Page numbering starts at 1
|
||||
Page *int32 `form:"page,omitempty" json:"page,omitempty"`
|
||||
|
||||
// PerPage The number of results to show per page.
|
||||
// PerPage The number of results to show per page. Use 0 to return only the total count.
|
||||
PerPage *int32 `form:"per_page,omitempty" json:"per_page,omitempty"`
|
||||
}
|
||||
|
||||
@@ -4257,7 +4288,7 @@ type GetReverseNamesIpv6Params struct {
|
||||
// Page The selected page. Page numbering starts at 1
|
||||
Page *int32 `form:"page,omitempty" json:"page,omitempty"`
|
||||
|
||||
// PerPage The number of results to show per page.
|
||||
// PerPage The number of results to show per page. Use 0 to return only the total count.
|
||||
PerPage *int32 `form:"per_page,omitempty" json:"per_page,omitempty"`
|
||||
}
|
||||
|
||||
@@ -4287,7 +4318,7 @@ type GetSamplesetsServerIdParams struct {
|
||||
// Page The selected page. Page numbering starts at 1
|
||||
Page *int32 `form:"page,omitempty" json:"page,omitempty"`
|
||||
|
||||
// PerPage The number of results to show per page.
|
||||
// PerPage The number of results to show per page. Use 0 to return only the total count.
|
||||
PerPage *int32 `form:"per_page,omitempty" json:"per_page,omitempty"`
|
||||
}
|
||||
|
||||
@@ -4314,7 +4345,7 @@ type GetServersParams struct {
|
||||
// Page The selected page. Page numbering starts at 1
|
||||
Page *int32 `form:"page,omitempty" json:"page,omitempty"`
|
||||
|
||||
// PerPage The number of results to show per page.
|
||||
// PerPage The number of results to show per page. Use 0 to return only the total count.
|
||||
PerPage *int32 `form:"per_page,omitempty" json:"per_page,omitempty"`
|
||||
}
|
||||
|
||||
@@ -4332,7 +4363,7 @@ type GetServersServerIdActionsParams struct {
|
||||
// Page The selected page. Page numbering starts at 1
|
||||
Page *int32 `form:"page,omitempty" json:"page,omitempty"`
|
||||
|
||||
// PerPage The number of results to show per page.
|
||||
// PerPage The number of results to show per page. Use 0 to return only the total count.
|
||||
PerPage *int32 `form:"per_page,omitempty" json:"per_page,omitempty"`
|
||||
}
|
||||
|
||||
@@ -4344,7 +4375,7 @@ type GetServersServerIdBackupsParams struct {
|
||||
// Page The selected page. Page numbering starts at 1
|
||||
Page *int32 `form:"page,omitempty" json:"page,omitempty"`
|
||||
|
||||
// PerPage The number of results to show per page.
|
||||
// PerPage The number of results to show per page. Use 0 to return only the total count.
|
||||
PerPage *int32 `form:"per_page,omitempty" json:"per_page,omitempty"`
|
||||
}
|
||||
|
||||
@@ -4356,7 +4387,7 @@ type GetServersServerIdKernelsParams struct {
|
||||
// Page The selected page. Page numbering starts at 1
|
||||
Page *int32 `form:"page,omitempty" json:"page,omitempty"`
|
||||
|
||||
// PerPage The number of results to show per page.
|
||||
// PerPage The number of results to show per page. Use 0 to return only the total count.
|
||||
PerPage *int32 `form:"per_page,omitempty" json:"per_page,omitempty"`
|
||||
}
|
||||
|
||||
@@ -4365,7 +4396,7 @@ type GetServersServerIdSnapshotsParams struct {
|
||||
// Page The selected page. Page numbering starts at 1
|
||||
Page *int32 `form:"page,omitempty" json:"page,omitempty"`
|
||||
|
||||
// PerPage The number of results to show per page.
|
||||
// PerPage The number of results to show per page. Use 0 to return only the total count.
|
||||
PerPage *int32 `form:"per_page,omitempty" json:"per_page,omitempty"`
|
||||
}
|
||||
|
||||
@@ -4374,7 +4405,7 @@ type GetServersServerIdSoftwareParams struct {
|
||||
// Page The selected page. Page numbering starts at 1
|
||||
Page *int32 `form:"page,omitempty" json:"page,omitempty"`
|
||||
|
||||
// PerPage The number of results to show per page.
|
||||
// PerPage The number of results to show per page. Use 0 to return only the total count.
|
||||
PerPage *int32 `form:"per_page,omitempty" json:"per_page,omitempty"`
|
||||
}
|
||||
|
||||
@@ -4389,7 +4420,7 @@ type GetSizesParams struct {
|
||||
// Page The selected page. Page numbering starts at 1
|
||||
Page *int32 `form:"page,omitempty" json:"page,omitempty"`
|
||||
|
||||
// PerPage The number of results to show per page.
|
||||
// PerPage The number of results to show per page. Use 0 to return only the total count.
|
||||
PerPage *int32 `form:"per_page,omitempty" json:"per_page,omitempty"`
|
||||
}
|
||||
|
||||
@@ -4398,7 +4429,7 @@ type GetSoftwareParams struct {
|
||||
// Page The selected page. Page numbering starts at 1
|
||||
Page *int32 `form:"page,omitempty" json:"page,omitempty"`
|
||||
|
||||
// PerPage The number of results to show per page.
|
||||
// PerPage The number of results to show per page. Use 0 to return only the total count.
|
||||
PerPage *int32 `form:"per_page,omitempty" json:"per_page,omitempty"`
|
||||
}
|
||||
|
||||
@@ -4407,7 +4438,7 @@ type GetSoftwareOperatingSystemOperatingSystemIdOrSlugParams struct {
|
||||
// Page The selected page. Page numbering starts at 1
|
||||
Page *int32 `form:"page,omitempty" json:"page,omitempty"`
|
||||
|
||||
// PerPage The number of results to show per page.
|
||||
// PerPage The number of results to show per page. Use 0 to return only the total count.
|
||||
PerPage *int32 `form:"per_page,omitempty" json:"per_page,omitempty"`
|
||||
}
|
||||
|
||||
@@ -4422,7 +4453,7 @@ type GetVpcsParams struct {
|
||||
// Page The selected page. Page numbering starts at 1
|
||||
Page *int32 `form:"page,omitempty" json:"page,omitempty"`
|
||||
|
||||
// PerPage The number of results to show per page.
|
||||
// PerPage The number of results to show per page. Use 0 to return only the total count.
|
||||
PerPage *int32 `form:"per_page,omitempty" json:"per_page,omitempty"`
|
||||
}
|
||||
|
||||
@@ -4452,7 +4483,7 @@ type GetVpcsVpcIdMembersParams struct {
|
||||
// Page The selected page. Page numbering starts at 1
|
||||
Page *int32 `form:"page,omitempty" json:"page,omitempty"`
|
||||
|
||||
// PerPage The number of results to show per page.
|
||||
// PerPage The number of results to show per page. Use 0 to return only the total count.
|
||||
PerPage *int32 `form:"per_page,omitempty" json:"per_page,omitempty"`
|
||||
}
|
||||
|
||||
|
||||
@@ -140,11 +140,10 @@ func loadBalancerSchema(ctx context.Context) schema.Schema {
|
||||
func (r *loadBalancerResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
|
||||
resp.Schema = loadBalancerSchema(ctx)
|
||||
|
||||
resp.Schema.Attributes["timeouts"] =
|
||||
timeouts.Attributes(ctx, timeouts.Opts{
|
||||
Create: true,
|
||||
Update: true,
|
||||
})
|
||||
resp.Schema.Attributes["timeouts"] = timeouts.Attributes(ctx, timeouts.Opts{
|
||||
Create: true,
|
||||
Update: true,
|
||||
})
|
||||
}
|
||||
|
||||
func (r *loadBalancerResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
|
||||
@@ -404,49 +403,35 @@ func (r *loadBalancerResource) ImportState(
|
||||
}
|
||||
|
||||
// Import by name
|
||||
var page int32 = 1
|
||||
perPage := int32(200)
|
||||
var loadBalancer binarylane.LoadBalancer
|
||||
var nextPage bool = true
|
||||
|
||||
for nextPage { // Need to paginate because the API does not support filtering by name
|
||||
params := binarylane.GetLoadBalancersParams{
|
||||
Page: &page,
|
||||
PerPage: &perPage,
|
||||
}
|
||||
|
||||
lbResp, err := r.bc.client.GetLoadBalancersWithResponse(ctx, ¶ms)
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError(fmt.Sprintf("Error getting load balancer for import: name=%s", req.ID), err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if lbResp.StatusCode() != http.StatusOK {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected HTTP status code getting load balancer for import",
|
||||
fmt.Sprintf("Received %s reading load balancer: name=%s. Details: %s", lbResp.Status(), req.ID,
|
||||
lbResp.Body))
|
||||
return
|
||||
}
|
||||
|
||||
loadBalancers := lbResp.JSON200.LoadBalancers
|
||||
for _, lb := range loadBalancers {
|
||||
if lb.Name == req.ID {
|
||||
loadBalancer = lb
|
||||
nextPage = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if lbResp.JSON200.Links == nil || lbResp.JSON200.Links.Pages.Next == nil {
|
||||
nextPage = false
|
||||
break
|
||||
}
|
||||
|
||||
page++
|
||||
params := binarylane.GetLoadBalancersParams{
|
||||
Name: &req.ID,
|
||||
}
|
||||
|
||||
diags := resp.State.SetAttribute(ctx, path.Root("id"), loadBalancer.Id)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
lbResp, err := r.bc.client.GetLoadBalancersWithResponse(ctx, ¶ms)
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError(fmt.Sprintf("Error getting load balancer for import: name=%s", req.ID), err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if lbResp.StatusCode() != http.StatusOK {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected HTTP status code getting load balancer for import",
|
||||
fmt.Sprintf("Received %s reading load balancer: name=%s. Details: %s", lbResp.Status(), req.ID,
|
||||
lbResp.Body))
|
||||
return
|
||||
}
|
||||
|
||||
for _, lb := range lbResp.JSON200.LoadBalancers {
|
||||
if lb.Name == req.ID {
|
||||
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("id"), lb.Id)...)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
resp.Diagnostics.AddError(
|
||||
"Load balancer not found",
|
||||
fmt.Sprintf("No load balancer named %q was found to import.", req.ID),
|
||||
)
|
||||
}
|
||||
|
||||
func setLoadBalancerModelState(ctx context.Context, data *loadBalancerDataModel, lb *binarylane.LoadBalancer) diag.Diagnostics {
|
||||
|
||||
@@ -28,7 +28,7 @@ func TestLoadBalancerResource(t *testing.T) {
|
||||
resource "binarylane_server" "test" {
|
||||
count = 2
|
||||
name = "tf-test-lb-server-${count.index}"
|
||||
region = "per"
|
||||
region = "` + testRegion + `"
|
||||
image = "debian-12"
|
||||
size = "std-min"
|
||||
password = "` + password + `"
|
||||
@@ -94,7 +94,7 @@ data "binarylane_load_balancer" "test" {
|
||||
resource "binarylane_server" "test" {
|
||||
count = 2
|
||||
name = "tf-test-lb-server-${count.index}"
|
||||
region = "per"
|
||||
region = "` + testRegion + `"
|
||||
image = "debian-12"
|
||||
size = "std-min"
|
||||
password = "` + password + `"
|
||||
|
||||
@@ -15,6 +15,24 @@ provider "binarylane" {
|
||||
# End of provider config
|
||||
|
||||
`
|
||||
|
||||
// planOnlyProviderConfig configures the provider with a placeholder token, for tests that
|
||||
// only ever plan and so never reach the API. providerConfig leaves the token to
|
||||
// BINARYLANE_API_TOKEN, which those tests would otherwise need set to run at all.
|
||||
planOnlyProviderConfig = `
|
||||
provider "binarylane" {
|
||||
api_token = "placeholder-never-used"
|
||||
}
|
||||
|
||||
# End of provider config
|
||||
|
||||
`
|
||||
|
||||
// testRegion is the BinaryLane region acceptance tests create servers in.
|
||||
// TEMPORARY: set to "mel" because "per" is intermittently returning "Unable to find a
|
||||
// suitable host for the requested server configuration". Revert to "per" once that's
|
||||
// resolved.
|
||||
testRegion = "mel"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -30,15 +30,14 @@ type serverDataSource struct {
|
||||
|
||||
type serverDataModel struct {
|
||||
resources.ServerModel
|
||||
PublicIpv4Addresses types.List `tfsdk:"public_ipv4_addresses"`
|
||||
PrivateIPv4Addresses types.List `tfsdk:"private_ipv4_addresses"`
|
||||
PublicIpv6Addresses types.List `tfsdk:"public_ipv6_addresses"`
|
||||
PrivateIpv6Addresses types.List `tfsdk:"private_ipv6_addresses"`
|
||||
Permalink types.String `tfsdk:"permalink"`
|
||||
Memory types.Int32 `tfsdk:"memory"`
|
||||
Disk types.Int32 `tfsdk:"disk"`
|
||||
SourceAndDestinationCheck types.Bool `tfsdk:"source_and_destination_check"`
|
||||
SeparatePrivateNetworkInterface types.Bool `tfsdk:"separate_private_network_interface"`
|
||||
PublicIpv4Addresses types.List `tfsdk:"public_ipv4_addresses"`
|
||||
PrivateIPv4Addresses types.List `tfsdk:"private_ipv4_addresses"`
|
||||
PublicIpv6Addresses types.List `tfsdk:"public_ipv6_addresses"`
|
||||
PrivateIpv6Addresses types.List `tfsdk:"private_ipv6_addresses"`
|
||||
Permalink types.String `tfsdk:"permalink"`
|
||||
Memory types.Int32 `tfsdk:"memory"`
|
||||
Disk types.Int32 `tfsdk:"disk"`
|
||||
SourceAndDestinationCheck types.Bool `tfsdk:"source_and_destination_check"`
|
||||
}
|
||||
|
||||
func (d *serverDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
|
||||
@@ -119,6 +118,8 @@ func (d *serverDataSource) Read(ctx context.Context, req datasource.ReadRequest,
|
||||
data.Permalink = types.StringValue(*serverResp.JSON200.Server.Permalink)
|
||||
data.Memory = types.Int32Value(serverResp.JSON200.Server.Memory)
|
||||
data.Disk = types.Int32Value(serverResp.JSON200.Server.Disk)
|
||||
data.Disks, diag = serverDisksToList(ctx, serverResp.JSON200.Server.Disks, data.Disks)
|
||||
diags.Append(diag...)
|
||||
data.SourceAndDestinationCheck = types.BoolPointerValue(serverResp.JSON200.Server.Networks.SourceAndDestinationCheck)
|
||||
data.SeparatePrivateNetworkInterface = types.BoolPointerValue(serverResp.JSON200.Server.Networks.SeparatePrivateNetworkInterface)
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ func TestServerFirewallRulesResource(t *testing.T) {
|
||||
|
||||
resource "binarylane_server" "test" {
|
||||
name = "tf-test-server-fw-rules"
|
||||
region = "per"
|
||||
region = "` + testRegion + `"
|
||||
image = "debian-12"
|
||||
size = "std-min"
|
||||
password = "` + password + `"
|
||||
@@ -90,7 +90,7 @@ data "binarylane_server_firewall_rules" "test" {
|
||||
|
||||
resource "binarylane_server" "test" {
|
||||
name = "tf-test-server-fw-rules"
|
||||
region = "per"
|
||||
region = "` + testRegion + `"
|
||||
image = "debian-12"
|
||||
size = "std-min"
|
||||
password = "` + password + `"
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"slices"
|
||||
@@ -355,8 +357,8 @@ func serverSchema(ctx context.Context) schema.Schema {
|
||||
},
|
||||
}
|
||||
|
||||
diskDescription := `The total storage in GB for this server. Leave null to accept the default for the size`
|
||||
diskValidValues := "Valid values must be a multiple of 5. If the value is greater than 60 GB, it must be a multiple of 10. " +
|
||||
diskDescription := "The total storage in GB for this server. Leave null to accept the default for the size."
|
||||
diskValidValues := " Valid values must be a multiple of 5. If the value is greater than 60 GB, it must be a multiple of 10. " +
|
||||
"if the value is greater than 200 GB, it must be a multiple of 100. "
|
||||
diskValidValuesMarkdown := ` Valid values:
|
||||
- must be a multiple of 5
|
||||
@@ -423,6 +425,21 @@ func (r *serverResource) ModifyPlan(ctx context.Context, req resource.ModifyPlan
|
||||
return
|
||||
}
|
||||
|
||||
// `disks` includes the primary, so more than one element means an additional disk.
|
||||
warnDisksMayRaceUserData := func() {
|
||||
if plan.UserData.ValueString() == "" || plan.Disks.IsNull() || plan.Disks.IsUnknown() || len(plan.Disks.Elements()) < 2 {
|
||||
return
|
||||
}
|
||||
resp.Diagnostics.AddAttributeWarning(
|
||||
path.Root("disks"),
|
||||
"Additional disks may race with user_data on first boot",
|
||||
"Additional disks are attached after the server boots into a fresh OS install (on create, or a "+
|
||||
"rebuild triggered by this plan), which can interrupt `user_data` (cloud-init) while it is "+
|
||||
"still running on first boot. cloud-init only runs user_data once per instance, so any "+
|
||||
"scripts that did not complete before the disk operations will not re-run on the next boot.",
|
||||
)
|
||||
}
|
||||
|
||||
if plan.SourceAndDestinationCheck.IsUnknown() {
|
||||
if plan.VpcId.IsNull() {
|
||||
plan.SourceAndDestinationCheck = types.BoolNull()
|
||||
@@ -451,6 +468,8 @@ func (r *serverResource) ModifyPlan(ctx context.Context, req resource.ModifyPlan
|
||||
}
|
||||
|
||||
if req.State.Raw.IsNull() {
|
||||
warnDisksMayRaceUserData()
|
||||
|
||||
// Creation plan, no further modification needed
|
||||
return
|
||||
}
|
||||
@@ -498,6 +517,7 @@ func (r *serverResource) ModifyPlan(ctx context.Context, req resource.ModifyPlan
|
||||
strings.Join(attrsRequiringRebuild, ", "),
|
||||
),
|
||||
)
|
||||
warnDisksMayRaceUserData()
|
||||
}
|
||||
|
||||
if !plan.Ipv6.Equal(state.Ipv6) {
|
||||
@@ -508,6 +528,11 @@ func (r *serverResource) ModifyPlan(ctx context.Context, req resource.ModifyPlan
|
||||
plan.PublicIpv6Addresses = types.ListNull(state.PublicIpv6Addresses.ElementType(ctx))
|
||||
plan.PrivateIpv6Addresses = types.ListNull(state.PrivateIpv6Addresses.ElementType(ctx))
|
||||
}
|
||||
} else {
|
||||
// Computed list attributes aren't carried forward from state by default, so without
|
||||
// this these would plan as unknown on every apply, even when ipv6 didn't change.
|
||||
plan.PublicIpv6Addresses = state.PublicIpv6Addresses
|
||||
plan.PrivateIpv6Addresses = state.PrivateIpv6Addresses
|
||||
}
|
||||
|
||||
// Use state for unknown disk/memory values, as long as server size is the same
|
||||
@@ -518,6 +543,32 @@ func (r *serverResource) ModifyPlan(ctx context.Context, req resource.ModifyPlan
|
||||
plan.Disk = state.Disk
|
||||
}
|
||||
|
||||
// A configured `disks` is planned by the attribute's own plan modifier, which matches each
|
||||
// disk with the one it corresponds to in prior state. Left unset, the disks are Binary Lane's
|
||||
// to manage, and what happens to them depends on `disk` — resolved just above, after that
|
||||
// plan modifier has already run.
|
||||
if config.Disks.IsNull() || config.Disks.IsUnknown() {
|
||||
// Computed list attributes aren't carried forward from state by default, so without this
|
||||
// `disks` would plan as unknown on every apply, even when nothing about it changed.
|
||||
plan.Disks = state.Disks
|
||||
|
||||
if state.Disks.IsNull() || state.Disks.IsUnknown() {
|
||||
plan.Disks = types.ListUnknown(resources.DisksValue{}.Type(ctx))
|
||||
} else if len(state.Disks.Elements()) == 1 && !plan.Disk.Equal(state.Disk) {
|
||||
// A resize resizes the primary disk to fill the new total, but only when it is the
|
||||
// server's only disk: with an additional disk it leaves every disk alone.
|
||||
plan.Disks = types.ListUnknown(resources.DisksValue{}.Type(ctx))
|
||||
|
||||
statePrimary, _, diags := splitDisks(ctx, state.Disks)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if statePrimary != nil && !plan.Disk.IsUnknown() &&
|
||||
float64(plan.Disk.ValueInt32()) < statePrimary.SizeGigabytes {
|
||||
resp.Diagnostics.Append(resources.DiskShrinkWarning(path.Root("disk"), "The primary disk",
|
||||
int64(statePrimary.SizeGigabytes), int64(plan.Disk.ValueInt32())))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if isAdvFeatChanged(&config.AdvancedFeatures, &state.AdvancedFeatures) {
|
||||
advFeatResp, err := r.bc.client.GetServersServerIdAvailableAdvancedFeaturesWithResponse(ctx, state.Id.ValueInt64())
|
||||
if err != nil {
|
||||
@@ -579,6 +630,11 @@ func (r *serverResource) ModifyPlan(ctx context.Context, req resource.ModifyPlan
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Computed object attributes aren't carried forward from state by default, so without
|
||||
// this `advanced_features` would plan as unknown on every apply, even when none of its
|
||||
// writable fields changed.
|
||||
plan.AdvancedFeatures = state.AdvancedFeatures
|
||||
}
|
||||
|
||||
// Save data into Terraform state
|
||||
@@ -622,8 +678,17 @@ func (r *serverResource) Create(ctx context.Context, req resource.CreateRequest,
|
||||
Options: &binarylane.SizeOptionsRequest{
|
||||
Ipv4Addresses: data.PublicIpv4Count.ValueInt32Pointer(),
|
||||
},
|
||||
Backups: data.Backups.ValueBoolPointer(),
|
||||
Ipv6: data.Ipv6.ValueBoolPointer(),
|
||||
Backups: data.Backups.ValueBoolPointer(),
|
||||
Ipv6: data.Ipv6.ValueBoolPointer(),
|
||||
SeparatePrivateNetworkInterface: data.SeparatePrivateNetworkInterface.ValueBoolPointer(),
|
||||
}
|
||||
|
||||
// The planned `disks` is unknown when it isn't configured, so the disks to create are read
|
||||
// from config, which is always known.
|
||||
configPrimary, configAdditional, diskDiags := splitDisks(ctx, config.Disks)
|
||||
resp.Diagnostics.Append(diskDiags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
if !data.Memory.IsNull() && !data.Memory.IsUnknown() {
|
||||
@@ -690,12 +755,12 @@ func (r *serverResource) Create(ctx context.Context, req resource.CreateRequest,
|
||||
data.PasswordChangeSupported = types.BoolValue(serverResp.JSON200.Server.PasswordChangeSupported)
|
||||
data.Memory = types.Int32Value(serverResp.JSON200.Server.Memory)
|
||||
data.Disk = types.Int32Value(serverResp.JSON200.Server.Disk)
|
||||
data.Disks, diags = serverDisksToList(ctx, serverResp.JSON200.Server.Disks, config.Disks)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
plannedSourceDestCheck := data.SourceAndDestinationCheck
|
||||
serverRespSourceDestCheck := types.BoolPointerValue(serverResp.JSON200.Server.Networks.SourceAndDestinationCheck)
|
||||
data.SourceAndDestinationCheck = serverRespSourceDestCheck
|
||||
plannedSeparatePrivateNic := data.SeparatePrivateNetworkInterface
|
||||
serverRespSeparatePrivateNic := types.BoolPointerValue(serverResp.JSON200.Server.Networks.SeparatePrivateNetworkInterface)
|
||||
data.SeparatePrivateNetworkInterface = serverRespSeparatePrivateNic
|
||||
data.SeparatePrivateNetworkInterface = types.BoolPointerValue(serverResp.JSON200.Server.Networks.SeparatePrivateNetworkInterface)
|
||||
|
||||
if serverResp.JSON200.Server.VpcId == nil {
|
||||
data.VpcIpv4Address = types.StringNull()
|
||||
@@ -771,14 +836,23 @@ func (r *serverResource) Create(ctx context.Context, req resource.CreateRequest,
|
||||
data.SourceAndDestinationCheck = plannedSourceDestCheck
|
||||
}
|
||||
|
||||
// Update separate_private_network_interface if needed
|
||||
if plannedSeparatePrivateNic.Equal(types.BoolPointerValue(Pointer(true))) {
|
||||
err := r.updateSeparatePrivateNetworkInterface(ctx, data.Id.ValueInt64(), true)
|
||||
// Carve the additional disks out of the server's total: it is created with a single primary
|
||||
// disk spanning all of it, so shrink that to make room, as Binary Lane's own UI does
|
||||
// (https://support.binarylane.com.au/support/solutions/articles/11000133468). If cloud-init's
|
||||
// growpart has already expanded the filesystem to fill the original primary, this can
|
||||
// corrupt it, and a disk can only be resized in place.
|
||||
if configPrimary != nil {
|
||||
finalDisks, err := r.reconcileServerDisks(
|
||||
ctx, data.Id.ValueInt64(), serverResp.JSON200.Server.Disks,
|
||||
configPrimary.SizeGigabytes, configAdditional, true,
|
||||
)
|
||||
data.Disks, diags = serverDisksToList(ctx, finalDisks, config.Disks)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError("Error updating separate private network interface", err.Error())
|
||||
resp.Diagnostics.AddError("Error creating additional disks", err.Error())
|
||||
return
|
||||
}
|
||||
data.SeparatePrivateNetworkInterface = plannedSeparatePrivateNic
|
||||
}
|
||||
|
||||
// One extra read to check the final state of enabled_advanced_features, needed because
|
||||
@@ -828,7 +902,6 @@ func (r *serverResource) Read(ctx context.Context, req resource.ReadRequest, res
|
||||
}
|
||||
|
||||
func (r *serverResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
|
||||
var diag diag.Diagnostics
|
||||
var config, plan, state serverResourceModel
|
||||
|
||||
// Read Terraform plan data into the model
|
||||
@@ -971,28 +1044,68 @@ func (r *serverResource) Update(ctx context.Context, req resource.UpdateRequest,
|
||||
}
|
||||
}
|
||||
|
||||
// The disks to reconcile come from config, which describes every disk when `disks` is set.
|
||||
// Left unset, the disks are Binary Lane's to manage and there is nothing to reconcile.
|
||||
configPrimary, configAdditional, diags := splitDisks(ctx, config.Disks)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
planDiskKnown := !plan.Disk.IsNull() && !plan.Disk.IsUnknown()
|
||||
diskChanged := planDiskKnown && !plan.Disk.Equal(state.Disk)
|
||||
sizeChanged := !plan.Size.Equal(state.Size)
|
||||
|
||||
// A `disk` or `size` change resizes the server, which can resize the primary disk with it, so
|
||||
// the disks are reconciled back to config after one of those too.
|
||||
reconcileDisks := configPrimary != nil &&
|
||||
(!plan.Disks.Equal(state.Disks) || diskChanged || sizeChanged)
|
||||
|
||||
persistDisks := func(disks []binarylane.Disk) {
|
||||
if disks == nil {
|
||||
return
|
||||
}
|
||||
var diags diag.Diagnostics
|
||||
state.Disks, diags = serverDisksToList(ctx, disks, plan.Disks)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
|
||||
}
|
||||
|
||||
// Free space before the resize below, which is where space to grow or add a disk comes from.
|
||||
var currentDisks []binarylane.Disk
|
||||
if reconcileDisks {
|
||||
var err error
|
||||
currentDisks, err = r.reconcileServerDisks(
|
||||
ctx, state.Id.ValueInt64(), nil, configPrimary.SizeGigabytes, configAdditional, false)
|
||||
persistDisks(currentDisks)
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError("Error reconciling server disks", err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Resize operation
|
||||
if !plan.Size.Equal(state.Size) ||
|
||||
!plan.Memory.IsNull() && !plan.Memory.IsUnknown() && !plan.Memory.Equal(state.Memory) ||
|
||||
!plan.Disk.IsNull() && !plan.Disk.IsUnknown() && !plan.Disk.Equal(state.Disk) ||
|
||||
memoryChanged := !plan.Memory.IsNull() && !plan.Memory.IsUnknown() && !plan.Memory.Equal(state.Memory)
|
||||
if sizeChanged || memoryChanged ||
|
||||
!plan.Image.Equal(state.Image) ||
|
||||
!plan.PublicIpv4Count.Equal(state.PublicIpv4Count) {
|
||||
!plan.PublicIpv4Count.Equal(state.PublicIpv4Count) ||
|
||||
diskChanged {
|
||||
|
||||
resizeReq := &binarylane.PostServersServerIdActionsResizeJSONRequestBody{
|
||||
Type: "resize",
|
||||
Options: &binarylane.ChangeSizeOptionsRequest{},
|
||||
}
|
||||
|
||||
if !plan.Size.Equal(state.Size) ||
|
||||
!plan.Memory.IsNull() && !plan.Memory.IsUnknown() && !plan.Memory.Equal(state.Memory) ||
|
||||
!plan.Disk.IsNull() && !plan.Disk.IsUnknown() && !plan.Disk.Equal(state.Disk) {
|
||||
|
||||
resizeReq.Size = plan.Size.ValueStringPointer()
|
||||
if sizeChanged || memoryChanged || diskChanged {
|
||||
if sizeChanged {
|
||||
resizeReq.Size = plan.Size.ValueStringPointer()
|
||||
}
|
||||
if !plan.Memory.IsUnknown() && !plan.Memory.IsNull() {
|
||||
resizeReq.Options.Memory = plan.Memory.ValueInt32Pointer()
|
||||
}
|
||||
if !plan.Disk.IsNull() && !plan.Disk.IsUnknown() {
|
||||
resizeReq.Options.Disk = plan.Disk.ValueInt32Pointer()
|
||||
if planDiskKnown {
|
||||
disk := plan.Disk.ValueInt32()
|
||||
resizeReq.Options.Disk = &disk
|
||||
}
|
||||
state.Size = plan.Size
|
||||
state.Memory = plan.Memory
|
||||
@@ -1053,6 +1166,9 @@ func (r *serverResource) Update(ctx context.Context, req resource.UpdateRequest,
|
||||
return
|
||||
}
|
||||
|
||||
// The resize can resize the primary disk, so anything read before it is stale.
|
||||
currentDisks = nil
|
||||
|
||||
if state.PublicIpv4Addresses.IsUnknown() || listContainsUnknown(ctx, state.PublicIpv4Addresses) || state.Memory.IsNull() || state.Memory.IsUnknown() {
|
||||
refreshNeeded = true
|
||||
}
|
||||
@@ -1064,6 +1180,18 @@ func (r *serverResource) Update(ctx context.Context, req resource.UpdateRequest,
|
||||
}
|
||||
}
|
||||
|
||||
// Grow the primary back to its target size, then grow and add the rest, now that the resize
|
||||
// has made room. currentDisks is nil if that resize ran, so they are re-read.
|
||||
if reconcileDisks {
|
||||
finalDisks, err := r.reconcileServerDisks(
|
||||
ctx, state.Id.ValueInt64(), currentDisks, configPrimary.SizeGigabytes, configAdditional, true)
|
||||
persistDisks(finalDisks)
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError("Error reconciling server disks", err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Change IPv6
|
||||
if !plan.Ipv6.Equal(state.Ipv6) {
|
||||
ipv6Resp, err := r.bc.client.PostServersServerIdActionsChangeIpv6WithResponse(
|
||||
@@ -1185,7 +1313,6 @@ func (r *serverResource) Update(ctx context.Context, req resource.UpdateRequest,
|
||||
resp.Diagnostics.AddError("Error updating advanced features", err.Error())
|
||||
return
|
||||
}
|
||||
resp.Diagnostics.Append(diag...)
|
||||
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
@@ -1519,6 +1646,9 @@ func (r *serverResource) fetchServerResourceState(ctx context.Context, state *se
|
||||
state.SeparatePrivateNetworkInterface = types.BoolPointerValue(serverResp.JSON200.Server.Networks.SeparatePrivateNetworkInterface)
|
||||
state.Memory = types.Int32Value(serverResp.JSON200.Server.Memory)
|
||||
state.Disk = types.Int32Value(serverResp.JSON200.Server.Disk)
|
||||
var readDiags diag.Diagnostics
|
||||
state.Disks, readDiags = serverDisksToList(ctx, serverResp.JSON200.Server.Disks, state.Disks)
|
||||
diags.Append(readDiags...)
|
||||
state.Backups = types.BoolValue(serverResp.JSON200.Server.NextBackupWindow != nil)
|
||||
state.Ipv6 = types.BoolValue(len(serverResp.JSON200.Server.Networks.V6) > 0)
|
||||
|
||||
@@ -1717,3 +1847,290 @@ func (r *serverResource) updateAdvancedFeatures(
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// serverDisksToList converts the server's disks into the `disks` attribute value, ordered to
|
||||
// match `order` — the value Terraform already holds, either planned or from prior state. A
|
||||
// list's elements must stay where they were planned, so a configuration can list disks in any
|
||||
// order as long as this keeps to it.
|
||||
func serverDisksToList(ctx context.Context, apiDisks []binarylane.Disk, order types.List) (types.List, diag.Diagnostics) {
|
||||
var diags diag.Diagnostics
|
||||
|
||||
var ordered []resources.DisksValue
|
||||
if !order.IsNull() && !order.IsUnknown() {
|
||||
diags.Append(order.ElementsAs(ctx, &ordered, true)...)
|
||||
}
|
||||
orderKeys := resources.DiskKeyer{}
|
||||
rank := make(map[resources.DiskKey]int, len(ordered))
|
||||
for i, d := range ordered {
|
||||
rank[orderKeys.Of(d.Primary.ValueBool(), d.Description.ValueString())] = i
|
||||
}
|
||||
|
||||
primaryFirst := func(d binarylane.Disk) int {
|
||||
if d.Primary {
|
||||
return 0
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
// Sort into a stable order first, to key the disks in and to fall back on.
|
||||
disks := slices.Clone(apiDisks)
|
||||
slices.SortStableFunc(disks, func(a, b binarylane.Disk) int {
|
||||
return cmp.Or(cmp.Compare(primaryFirst(a), primaryFirst(b)), cmp.Compare(a.Id, b.Id))
|
||||
})
|
||||
|
||||
// Disks the order doesn't mention keep that order, after those it does.
|
||||
diskKeys := resources.DiskKeyer{}
|
||||
rankById := make(map[int64]int, len(disks))
|
||||
for _, d := range disks {
|
||||
r, ranked := rank[diskKeys.Of(d.Primary, diskDescription(d))]
|
||||
if !ranked {
|
||||
r = len(rank)
|
||||
}
|
||||
rankById[d.Id] = r
|
||||
}
|
||||
slices.SortStableFunc(disks, func(a, b binarylane.Disk) int {
|
||||
return cmp.Compare(rankById[a.Id], rankById[b.Id])
|
||||
})
|
||||
|
||||
list, listDiags := types.ListValueFrom(ctx, resources.DisksValue{}.Type(ctx), disks)
|
||||
diags.Append(listDiags...)
|
||||
return list, diags
|
||||
}
|
||||
|
||||
// splitDisks divides a `disks` list into its primary entry and the additional disks, as the API's
|
||||
// own type: binarylane.Disk carries tfsdk tags for exactly the attributes `disks` has, so the
|
||||
// values reflect straight into it. The attributes Binary Lane assigns are null in a configuration
|
||||
// and come back as their zero value. primary is nil when the list is null or unknown, or has no
|
||||
// entry with `primary = true`.
|
||||
func splitDisks(ctx context.Context, list types.List) (primary *binarylane.Disk, additional []binarylane.Disk, diags diag.Diagnostics) {
|
||||
if list.IsNull() || list.IsUnknown() {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
var disks []binarylane.Disk
|
||||
diags = list.ElementsAs(ctx, &disks, true)
|
||||
if diags.HasError() {
|
||||
return nil, nil, diags
|
||||
}
|
||||
|
||||
for i, d := range disks {
|
||||
if d.Primary && primary == nil {
|
||||
primary = &disks[i]
|
||||
continue
|
||||
}
|
||||
additional = append(additional, d)
|
||||
}
|
||||
return primary, additional, diags
|
||||
}
|
||||
|
||||
// reconcileServerDisks brings the server's disks in line with desiredPrimary and
|
||||
// desiredAdditional, and returns them as they stand afterwards, re-read if anything changed —
|
||||
// including after a failure, since partially applied disk changes are not rolled back. current
|
||||
// is the disks as last read, or nil to read them here.
|
||||
//
|
||||
// Deleting and shrinking only free space, so they always run. Growing the primary, growing a
|
||||
// disk and adding one all claim space the server's total may not have yet, so they wait for
|
||||
// growAndAdd: Update calls this before its resize action with growAndAdd false and after it
|
||||
// with true, while Create has no resize of its own and always passes true.
|
||||
func (r *serverResource) reconcileServerDisks(
|
||||
ctx context.Context,
|
||||
serverId int64,
|
||||
current []binarylane.Disk,
|
||||
desiredPrimary float64,
|
||||
desiredAdditional []binarylane.Disk,
|
||||
growAndAdd bool,
|
||||
) ([]binarylane.Disk, error) {
|
||||
if current == nil {
|
||||
var err error
|
||||
if current, err = r.fetchServerDisks(ctx, serverId); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
mutated, err := r.applyDiskChanges(ctx, serverId, current, desiredPrimary, desiredAdditional, growAndAdd)
|
||||
if !mutated {
|
||||
return current, err
|
||||
}
|
||||
disks, fetchErr := r.fetchServerDisks(ctx, serverId)
|
||||
if fetchErr != nil {
|
||||
return current, errors.Join(err, fetchErr)
|
||||
}
|
||||
return disks, err
|
||||
}
|
||||
|
||||
// applyDiskChanges makes the changes reconcileServerDisks needs, reporting whether it attempted
|
||||
// any.
|
||||
func (r *serverResource) applyDiskChanges(
|
||||
ctx context.Context,
|
||||
serverId int64,
|
||||
current []binarylane.Disk,
|
||||
desiredPrimary float64,
|
||||
desiredAdditional []binarylane.Disk,
|
||||
growAndAdd bool,
|
||||
) (mutated bool, err error) {
|
||||
desiredKeys := make([]resources.DiskKey, len(desiredAdditional))
|
||||
desiredSizes := make(map[resources.DiskKey]float64, len(desiredAdditional))
|
||||
keyer := resources.DiskKeyer{}
|
||||
for i, d := range desiredAdditional {
|
||||
desiredKeys[i] = keyer.Of(false, diskDescription(d))
|
||||
desiredSizes[desiredKeys[i]] = d.SizeGigabytes
|
||||
}
|
||||
|
||||
// Keyed by id order, which is the order the desired disks were planned against.
|
||||
byId := slices.Clone(current)
|
||||
slices.SortStableFunc(byId, func(a, b binarylane.Disk) int { return cmp.Compare(a.Id, b.Id) })
|
||||
|
||||
var primary *binarylane.Disk
|
||||
currentKeys := make(map[int64]resources.DiskKey, len(current))
|
||||
currentByKey := make(map[resources.DiskKey]binarylane.Disk, len(current))
|
||||
keyer = resources.DiskKeyer{}
|
||||
for i, d := range byId {
|
||||
if d.Primary {
|
||||
primary = &byId[i]
|
||||
continue
|
||||
}
|
||||
key := keyer.Of(false, diskDescription(d))
|
||||
currentKeys[d.Id] = key
|
||||
currentByKey[key] = d
|
||||
}
|
||||
|
||||
// Delete disks that are no longer wanted and shrink those that are getting smaller.
|
||||
for _, d := range current {
|
||||
if d.Primary {
|
||||
continue
|
||||
}
|
||||
desired, wanted := desiredSizes[currentKeys[d.Id]]
|
||||
switch {
|
||||
case !wanted:
|
||||
mutated = true
|
||||
if err := r.deleteServerDisk(ctx, serverId, d.Id); err != nil {
|
||||
return true, err
|
||||
}
|
||||
case desired < d.SizeGigabytes:
|
||||
mutated = true
|
||||
if err := r.resizeServerDisk(ctx, serverId, d.Id, desired); err != nil {
|
||||
return true, err
|
||||
}
|
||||
}
|
||||
}
|
||||
// The primary shrinks before a server-level resize and grows after it, never both.
|
||||
if primary != nil && (desiredPrimary < primary.SizeGigabytes ||
|
||||
(growAndAdd && desiredPrimary > primary.SizeGigabytes)) {
|
||||
mutated = true
|
||||
if err := r.resizeServerDisk(ctx, serverId, primary.Id, desiredPrimary); err != nil {
|
||||
return true, err
|
||||
}
|
||||
}
|
||||
|
||||
if !growAndAdd {
|
||||
return mutated, nil
|
||||
}
|
||||
|
||||
for i, d := range desiredAdditional {
|
||||
if existing, ok := currentByKey[desiredKeys[i]]; ok {
|
||||
if d.SizeGigabytes > existing.SizeGigabytes {
|
||||
mutated = true
|
||||
if err := r.resizeServerDisk(ctx, serverId, existing.Id, d.SizeGigabytes); err != nil {
|
||||
return true, err
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
mutated = true
|
||||
if err := r.addServerDisk(ctx, serverId, diskDescription(d), d.SizeGigabytes); err != nil {
|
||||
return true, err
|
||||
}
|
||||
}
|
||||
return mutated, nil
|
||||
}
|
||||
|
||||
// diskDescription returns a disk's description, which is unset for a disk added without one.
|
||||
func diskDescription(d binarylane.Disk) string {
|
||||
if d.Description == nil {
|
||||
return ""
|
||||
}
|
||||
return *d.Description
|
||||
}
|
||||
|
||||
func (r *serverResource) fetchServerDisks(ctx context.Context, serverId int64) ([]binarylane.Disk, error) {
|
||||
resp, err := r.bc.client.GetServersServerIdWithResponse(ctx, serverId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error fetching server disks: server_id=%d, error: %w", serverId, err)
|
||||
}
|
||||
if resp.StatusCode() != http.StatusOK {
|
||||
return nil, fmt.Errorf("unexpected HTTP status code fetching server disks: server_id=%d, status=%s, body: %s", serverId, resp.Status(), resp.Body)
|
||||
}
|
||||
return resp.JSON200.Server.Disks, nil
|
||||
}
|
||||
|
||||
func (r *serverResource) resizeServerDisk(ctx context.Context, serverId int64, diskId int64, sizeGigabytes float64) error {
|
||||
tflog.Info(ctx, fmt.Sprintf("Resizing disk: server_id=%d, disk_id=%d, size_gigabytes=%g", serverId, diskId, sizeGigabytes))
|
||||
|
||||
resizeResp, err := r.bc.client.PostServersServerIdActionsResizeDiskWithResponse(ctx, serverId, binarylane.ResizeDisk{
|
||||
Type: binarylane.ResizeDiskTypeResizeDisk,
|
||||
DiskId: diskId,
|
||||
SizeGigabytes: int32(sizeGigabytes),
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("error resizing disk: server_id=%d, disk_id=%d, error: %w", serverId, diskId, err)
|
||||
}
|
||||
if resizeResp.StatusCode() != http.StatusOK {
|
||||
return fmt.Errorf("unexpected HTTP status code resizing disk: server_id=%d, disk_id=%d, details: %s", serverId, diskId, resizeResp.Body)
|
||||
}
|
||||
|
||||
err = r.waitForServerAction(ctx, serverId, resizeResp.JSON200.Action.Id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error resizing disk: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *serverResource) deleteServerDisk(ctx context.Context, serverId int64, diskId int64) error {
|
||||
tflog.Info(ctx, fmt.Sprintf("Deleting disk: server_id=%d, disk_id=%d", serverId, diskId))
|
||||
|
||||
deleteResp, err := r.bc.client.PostServersServerIdActionsDeleteDiskWithResponse(ctx, serverId, binarylane.DeleteDisk{
|
||||
Type: binarylane.DeleteDiskTypeDeleteDisk,
|
||||
DiskId: diskId,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("error deleting disk: server_id=%d, disk_id=%d, error: %w", serverId, diskId, err)
|
||||
}
|
||||
if deleteResp.StatusCode() != http.StatusOK {
|
||||
return fmt.Errorf("unexpected HTTP status code deleting disk: server_id=%d, disk_id=%d, details: %s", serverId, diskId, deleteResp.Body)
|
||||
}
|
||||
|
||||
err = r.waitForServerAction(ctx, serverId, deleteResp.JSON200.Action.Id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error deleting disk: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *serverResource) addServerDisk(ctx context.Context, serverId int64, description string, sizeGigabytes float64) error {
|
||||
tflog.Info(ctx, fmt.Sprintf("Adding disk: server_id=%d, description=%s, size_gigabytes=%g", serverId, description, sizeGigabytes))
|
||||
|
||||
addDisk := binarylane.AddDisk{
|
||||
Type: binarylane.AddDiskTypeAddDisk,
|
||||
SizeGigabytes: int32(sizeGigabytes),
|
||||
}
|
||||
if description != "" {
|
||||
addDisk.Description = &description
|
||||
}
|
||||
|
||||
addResp, err := r.bc.client.PostServersServerIdActionsAddDiskWithResponse(ctx, serverId, addDisk)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error adding disk: server_id=%d, description=%s, error: %w", serverId, description, err)
|
||||
}
|
||||
if addResp.StatusCode() != http.StatusOK {
|
||||
return fmt.Errorf("unexpected HTTP status code adding disk: server_id=%d, description=%s, details: %s", serverId, description, addResp.Body)
|
||||
}
|
||||
|
||||
err = r.waitForServerAction(ctx, serverId, addResp.JSON200.Action.Id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error adding disk: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -23,6 +23,10 @@ func TestServerResource(t *testing.T) {
|
||||
sshPublicKeyInitial := GenerateTestPublicKey(t)
|
||||
sshPublicKeyUpdated := GenerateTestPublicKey(t)
|
||||
|
||||
// Captured while "zeta" still exists, then checked once it is gone and the disks after it
|
||||
// have shifted down a position.
|
||||
var alphaDiskId, betaDiskId string
|
||||
|
||||
resource.ParallelTest(t, resource.TestCase{
|
||||
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
|
||||
Steps: []resource.TestStep{
|
||||
@@ -49,7 +53,7 @@ resource "binarylane_ssh_key" "updated" {
|
||||
|
||||
resource "binarylane_server" "test" {
|
||||
name = "tf-test-server-resource"
|
||||
region = "per"
|
||||
region = "` + testRegion + `"
|
||||
image = "debian-11"
|
||||
size = "std-min"
|
||||
memory = 1152
|
||||
@@ -77,11 +81,16 @@ data "binarylane_server" "test" {
|
||||
// Verify resource values
|
||||
resource.TestCheckResourceAttrSet("binarylane_server.test", "id"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "name", "tf-test-server-resource"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "region", "per"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "region", testRegion),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "image", "debian-11"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "size", "std-min"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "memory", "1152"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disk", "20"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.#", "1"),
|
||||
resource.TestCheckResourceAttrSet("binarylane_server.test", "disks.0.id"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.0.primary", "true"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.0.description", "SYSTEM"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.0.size_gigabytes", "20"),
|
||||
resource.TestCheckResourceAttrSet("binarylane_server.test", "vpc_id"),
|
||||
resource.TestCheckResourceAttrSet("binarylane_server.test", "vpc_ipv4_address"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "public_ipv4_count", "1"),
|
||||
@@ -114,7 +123,7 @@ echo "Hello World" > /var/tmp/output.txt
|
||||
// Verify data source values
|
||||
resource.TestCheckResourceAttrPair("data.binarylane_server.test", "id", "binarylane_server.test", "id"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_server.test", "name", "tf-test-server-resource"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_server.test", "region", "per"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_server.test", "region", testRegion),
|
||||
resource.TestCheckResourceAttr("data.binarylane_server.test", "image", "debian-11"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_server.test", "size", "std-min"),
|
||||
resource.TestCheckResourceAttrSet("data.binarylane_server.test", "vpc_id"),
|
||||
@@ -125,6 +134,11 @@ echo "Hello World" > /var/tmp/output.txt
|
||||
`),
|
||||
resource.TestCheckResourceAttr("data.binarylane_server.test", "memory", "1152"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_server.test", "disk", "20"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_server.test", "disks.#", "1"),
|
||||
resource.TestCheckResourceAttrSet("data.binarylane_server.test", "disks.0.id"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_server.test", "disks.0.primary", "true"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_server.test", "disks.0.description", "SYSTEM"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_server.test", "disks.0.size_gigabytes", "20"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_server.test", "backups", "true"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_server.test", "port_blocking", "false"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_server.test", "source_and_destination_check", "false"),
|
||||
@@ -180,10 +194,16 @@ resource "binarylane_ssh_key" "updated" {
|
||||
|
||||
resource "binarylane_server" "test" {
|
||||
name = "tf-test-server-resource-2"
|
||||
region = "per"
|
||||
region = "` + testRegion + `"
|
||||
image = "debian-12"
|
||||
size = "std-1vcpu"
|
||||
disk = "45"
|
||||
size = "std-min"
|
||||
disk = 40
|
||||
disks = [
|
||||
{ primary = true, size_gigabytes = 25 },
|
||||
{ description = "zeta", size_gigabytes = 5 },
|
||||
{ description = "alpha", size_gigabytes = 5 },
|
||||
{ description = "beta", size_gigabytes = 5 },
|
||||
]
|
||||
password = "` + password1 + `"
|
||||
vpc_id = null
|
||||
public_ipv4_count = 0
|
||||
@@ -207,9 +227,34 @@ EOT
|
||||
`,
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "name", "tf-test-server-resource-2"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "size", "std-1vcpu"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "memory", "2048"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disk", "45"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "size", "std-min"),
|
||||
// `memory` is unset here and `size` is unchanged, so it carries forward
|
||||
// the 1152 set in the previous step.
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "memory", "1152"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disk", "40"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.#", "4"),
|
||||
resource.TestCheckResourceAttrSet("binarylane_server.test", "disks.0.id"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.0.primary", "true"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.0.description", "SYSTEM"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.0.size_gigabytes", "25"),
|
||||
resource.TestCheckResourceAttrSet("binarylane_server.test", "disks.1.id"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.1.primary", "false"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.1.description", "zeta"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.1.size_gigabytes", "5"),
|
||||
resource.TestCheckResourceAttrWith("binarylane_server.test", "disks.2.id", func(value string) error {
|
||||
alphaDiskId = value
|
||||
return nil
|
||||
}),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.2.primary", "false"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.2.description", "alpha"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.2.size_gigabytes", "5"),
|
||||
resource.TestCheckResourceAttrWith("binarylane_server.test", "disks.3.id", func(value string) error {
|
||||
betaDiskId = value
|
||||
return nil
|
||||
}),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.3.primary", "false"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.3.description", "beta"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.3.size_gigabytes", "5"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "public_ipv4_count", "0"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "public_ipv4_addresses.#", "0"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "image", "debian-12"),
|
||||
@@ -254,10 +299,16 @@ resource "binarylane_ssh_key" "updated" {
|
||||
|
||||
resource "binarylane_server" "test" {
|
||||
name = "tf-test-server-resource-2"
|
||||
region = "per"
|
||||
region = "` + testRegion + `"
|
||||
image = "debian-12"
|
||||
size = "std-1vcpu"
|
||||
disk = "45"
|
||||
size = "std-min"
|
||||
disk = 35
|
||||
disks = [
|
||||
{ primary = true, size_gigabytes = 15 },
|
||||
{ description = "alpha", size_gigabytes = 10 },
|
||||
{ description = "beta", size_gigabytes = 5 },
|
||||
{ description = "delta", size_gigabytes = 5 },
|
||||
]
|
||||
password = "` + password2 + `"
|
||||
vpc_id = null
|
||||
public_ipv4_count = 0
|
||||
@@ -278,6 +329,288 @@ EOT
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "name", "tf-test-server-resource-2"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "password", password2),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disk", "35"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.#", "4"),
|
||||
resource.TestCheckResourceAttrSet("binarylane_server.test", "disks.0.id"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.0.primary", "true"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.0.description", "SYSTEM"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.0.size_gigabytes", "15"),
|
||||
// Removing "zeta" shifts these down a position, but each keeps the disk it
|
||||
// had: they are matched to prior state by description, not by index.
|
||||
resource.TestCheckResourceAttrWith("binarylane_server.test", "disks.1.id", func(value string) error {
|
||||
if value != alphaDiskId {
|
||||
return fmt.Errorf("disk \"alpha\" has id %s, want %s", value, alphaDiskId)
|
||||
}
|
||||
return nil
|
||||
}),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.1.primary", "false"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.1.description", "alpha"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.1.size_gigabytes", "10"),
|
||||
resource.TestCheckResourceAttrWith("binarylane_server.test", "disks.2.id", func(value string) error {
|
||||
if value != betaDiskId {
|
||||
return fmt.Errorf("disk \"beta\" has id %s, want %s", value, betaDiskId)
|
||||
}
|
||||
return nil
|
||||
}),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.2.primary", "false"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.2.description", "beta"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.2.size_gigabytes", "5"),
|
||||
resource.TestCheckResourceAttrSet("binarylane_server.test", "disks.3.id"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.3.primary", "false"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.3.description", "delta"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.3.size_gigabytes", "5"),
|
||||
),
|
||||
},
|
||||
// Dropping `disks` leaves the server's disks alone: growing the total here only
|
||||
// adds unallocated space, since the primary is not the only disk.
|
||||
{
|
||||
Config: providerConfig + `
|
||||
resource "binarylane_ssh_key" "updated" {
|
||||
name = "tf-test-server-resource-updated"
|
||||
public_key = "` + sshPublicKeyUpdated + `"
|
||||
default = true
|
||||
}
|
||||
|
||||
resource "binarylane_server" "test" {
|
||||
name = "tf-test-server-resource-2"
|
||||
region = "` + testRegion + `"
|
||||
image = "debian-12"
|
||||
size = "std-min"
|
||||
disk = 50
|
||||
password = "` + password2 + `"
|
||||
vpc_id = null
|
||||
public_ipv4_count = 0
|
||||
ssh_keys = [binarylane_ssh_key.updated.id]
|
||||
|
||||
user_data = <<EOT
|
||||
#cloud-config
|
||||
echo "Hello Whitespace" > /var/tmp/output.txt
|
||||
|
||||
|
||||
EOT
|
||||
}
|
||||
`,
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disk", "50"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.#", "4"),
|
||||
resource.TestCheckResourceAttrSet("binarylane_server.test", "disks.0.id"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.0.primary", "true"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.0.description", "SYSTEM"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.0.size_gigabytes", "15"),
|
||||
resource.TestCheckResourceAttrSet("binarylane_server.test", "disks.1.id"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.1.primary", "false"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.1.description", "alpha"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.1.size_gigabytes", "10"),
|
||||
resource.TestCheckResourceAttrSet("binarylane_server.test", "disks.2.id"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.2.primary", "false"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.2.description", "beta"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.2.size_gigabytes", "5"),
|
||||
resource.TestCheckResourceAttrSet("binarylane_server.test", "disks.3.id"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.3.primary", "false"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.3.description", "delta"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.3.size_gigabytes", "5"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// TestServerResourceDisksValidation exercises the plan-time `disks` validators. Every case only
|
||||
// plans a fresh server, so no infrastructure is created.
|
||||
func TestServerResourceDisksValidation(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
// attributes are added to an otherwise valid server resource.
|
||||
attributes string
|
||||
// expectErr is the error the plan must fail with, or empty if it must succeed.
|
||||
expectErr string
|
||||
}{
|
||||
{
|
||||
name: "no primary disk",
|
||||
attributes: `disks = [{ description = "data1", size_gigabytes = 10 }]`,
|
||||
expectErr: "Missing primary disk",
|
||||
},
|
||||
{
|
||||
name: "empty disks list",
|
||||
attributes: `disks = []`,
|
||||
expectErr: "Missing primary disk",
|
||||
},
|
||||
{
|
||||
name: "two primary disks",
|
||||
attributes: `disks = [
|
||||
{ primary = true, size_gigabytes = 20 },
|
||||
{ primary = true, size_gigabytes = 10 },
|
||||
]`,
|
||||
expectErr: "Multiple primary disks",
|
||||
},
|
||||
{
|
||||
// The primary disk's description is assigned by Binary Lane, not by the user.
|
||||
name: "primary disk with a description",
|
||||
attributes: `disks = [{ primary = true, description = "SYSTEM", size_gigabytes = 20 }]`,
|
||||
expectErr: "Primary disk description is server-assigned",
|
||||
},
|
||||
{
|
||||
name: "disks exceeding the total",
|
||||
attributes: `disk = 45
|
||||
disks = [
|
||||
{ primary = true, size_gigabytes = 30 },
|
||||
{ description = "data1", size_gigabytes = 20 },
|
||||
]`,
|
||||
expectErr: "Disks exceed total disk allocation",
|
||||
},
|
||||
{
|
||||
name: "disk below the minimum",
|
||||
attributes: `disk = 10`,
|
||||
expectErr: "Attribute disk",
|
||||
},
|
||||
{
|
||||
// Binary Lane allows duplicate descriptions, and so does this provider.
|
||||
name: "duplicate descriptions",
|
||||
attributes: `disks = [
|
||||
{ primary = true, size_gigabytes = 20 },
|
||||
{ description = "data", size_gigabytes = 5 },
|
||||
{ description = "data", size_gigabytes = 10 },
|
||||
]`,
|
||||
},
|
||||
{
|
||||
// Also valid with room to spare, leaving the difference unallocated.
|
||||
name: "disks filling the total exactly",
|
||||
attributes: `disk = 40
|
||||
disks = [
|
||||
{ primary = true, size_gigabytes = 30 },
|
||||
{ description = "data1", size_gigabytes = 10 },
|
||||
]`,
|
||||
},
|
||||
{
|
||||
name: "disks with the total left unset",
|
||||
attributes: `disks = [
|
||||
{ primary = true, size_gigabytes = 30 },
|
||||
{ description = "data1", size_gigabytes = 10 },
|
||||
]`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
step := resource.TestStep{
|
||||
Config: planOnlyProviderConfig + fmt.Sprintf(`
|
||||
resource "binarylane_server" "test" {
|
||||
name = "tf-test-disks-validation"
|
||||
region = %q
|
||||
image = "debian-12"
|
||||
size = "std-min"
|
||||
public_ipv4_count = 0
|
||||
%s
|
||||
}
|
||||
`, testRegion, tt.attributes),
|
||||
PlanOnly: true,
|
||||
ExpectNonEmptyPlan: true,
|
||||
}
|
||||
if tt.expectErr != "" {
|
||||
step.ExpectError = regexp.MustCompile(tt.expectErr)
|
||||
}
|
||||
resource.UnitTest(t, resource.TestCase{
|
||||
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
|
||||
Steps: []resource.TestStep{step},
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestServerResourceCreateWithDisks(t *testing.T) {
|
||||
// Must assign a password to the server or Binary Lane will send emails
|
||||
password := GenerateTestPassword(t)
|
||||
|
||||
resource.ParallelTest(t, resource.TestCase{
|
||||
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: providerConfig + `
|
||||
resource "binarylane_server" "test" {
|
||||
name = "tf-test-server-create-disks"
|
||||
region = "` + testRegion + `"
|
||||
image = "debian-12"
|
||||
size = "std-min"
|
||||
public_ipv4_count = 0
|
||||
password = "` + password + `"
|
||||
disk = 40
|
||||
disks = [
|
||||
{ primary = true, size_gigabytes = 20 },
|
||||
{ description = "data", size_gigabytes = 10 },
|
||||
{ description = "data", size_gigabytes = 5 },
|
||||
]
|
||||
}
|
||||
`,
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
// 5 GB of the total is left unallocated.
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disk", "40"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.#", "3"),
|
||||
resource.TestCheckResourceAttrSet("binarylane_server.test", "disks.0.id"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.0.primary", "true"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.0.description", "SYSTEM"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.0.size_gigabytes", "20"),
|
||||
resource.TestCheckResourceAttrSet("binarylane_server.test", "disks.1.id"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.1.primary", "false"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.1.description", "data"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.1.size_gigabytes", "10"),
|
||||
resource.TestCheckResourceAttrSet("binarylane_server.test", "disks.2.id"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.2.primary", "false"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.2.description", "data"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.2.size_gigabytes", "5"),
|
||||
),
|
||||
},
|
||||
// The same disks in a different order, which is not a change.
|
||||
{
|
||||
Config: providerConfig + `
|
||||
resource "binarylane_server" "test" {
|
||||
name = "tf-test-server-create-disks"
|
||||
region = "` + testRegion + `"
|
||||
image = "debian-12"
|
||||
size = "std-min"
|
||||
public_ipv4_count = 0
|
||||
password = "` + password + `"
|
||||
disk = 40
|
||||
disks = [
|
||||
{ description = "data", size_gigabytes = 10 },
|
||||
{ primary = true, size_gigabytes = 20 },
|
||||
{ description = "data", size_gigabytes = 5 },
|
||||
]
|
||||
}
|
||||
|
||||
data "binarylane_server" "test" {
|
||||
depends_on = [binarylane_server.test]
|
||||
|
||||
id = binarylane_server.test.id
|
||||
}
|
||||
`,
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
// The resource keeps the order the configuration lists the disks in
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.#", "3"),
|
||||
resource.TestCheckResourceAttrSet("binarylane_server.test", "disks.0.id"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.0.primary", "false"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.0.description", "data"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.0.size_gigabytes", "10"),
|
||||
resource.TestCheckResourceAttrSet("binarylane_server.test", "disks.1.id"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.1.primary", "true"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.1.description", "SYSTEM"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.1.size_gigabytes", "20"),
|
||||
resource.TestCheckResourceAttrSet("binarylane_server.test", "disks.2.id"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.2.primary", "false"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.2.description", "data"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disks.2.size_gigabytes", "5"),
|
||||
|
||||
// The data source has no order of its own, so it lists the primary disk
|
||||
// first and the rest by id
|
||||
resource.TestCheckResourceAttr("data.binarylane_server.test", "disks.#", "3"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_server.test", "disks.0.primary", "true"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_server.test", "disks.0.description", "SYSTEM"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_server.test", "disks.0.size_gigabytes", "20"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_server.test", "disks.1.primary", "false"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_server.test", "disks.1.description", "data"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_server.test", "disks.1.size_gigabytes", "10"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_server.test", "disks.2.primary", "false"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_server.test", "disks.2.description", "data"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_server.test", "disks.2.size_gigabytes", "5"),
|
||||
),
|
||||
},
|
||||
},
|
||||
@@ -297,7 +630,7 @@ func TestServerResourceRename(t *testing.T) {
|
||||
|
||||
resource "binarylane_server" "test" {
|
||||
name = "tf-test-server-rename-1"
|
||||
region = "per"
|
||||
region = "` + testRegion + `"
|
||||
image = "debian-11"
|
||||
size = "std-min"
|
||||
public_ipv4_count = 0
|
||||
@@ -310,7 +643,7 @@ resource "binarylane_server" "test" {
|
||||
Config: providerConfig + `
|
||||
resource "binarylane_server" "test" {
|
||||
name = "tf-test-server-rename-2"
|
||||
region = "per"
|
||||
region = "` + testRegion + `"
|
||||
image = "debian-11"
|
||||
size = "std-min"
|
||||
public_ipv4_count = 0
|
||||
@@ -319,7 +652,7 @@ resource "binarylane_server" "test" {
|
||||
`,
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "name", "tf-test-server-rename-2"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "region", "per"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "region", testRegion),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "image", "debian-11"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "size", "std-min"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "password", password),
|
||||
@@ -341,7 +674,7 @@ func TestServerVpcIpv4Change(t *testing.T) {
|
||||
Config: providerConfig + `
|
||||
resource "binarylane_server" "test" {
|
||||
name = "tf-test-server-vpcipv4-1"
|
||||
region = "per"
|
||||
region = "` + testRegion + `"
|
||||
image = "debian-11"
|
||||
size = "std-min"
|
||||
public_ipv4_count = 0
|
||||
@@ -367,7 +700,7 @@ resource "binarylane_vpc" "test2" {
|
||||
|
||||
resource "binarylane_server" "test" {
|
||||
name = "tf-test-server-vpcipv4-1"
|
||||
region = "per"
|
||||
region = "` + testRegion + `"
|
||||
image = "debian-11"
|
||||
size = "std-min"
|
||||
public_ipv4_count = 0
|
||||
@@ -407,7 +740,7 @@ resource "binarylane_vpc" "test2" {
|
||||
|
||||
resource "binarylane_server" "test" {
|
||||
name = "tf-test-server-vpcipv4-1"
|
||||
region = "per"
|
||||
region = "` + testRegion + `"
|
||||
image = "debian-11"
|
||||
size = "std-min"
|
||||
public_ipv4_count = 0
|
||||
@@ -447,7 +780,7 @@ resource "binarylane_vpc" "test2" {
|
||||
|
||||
resource "binarylane_server" "test" {
|
||||
name = "tf-test-server-vpcipv4-1"
|
||||
region = "per"
|
||||
region = "` + testRegion + `"
|
||||
image = "debian-11"
|
||||
size = "std-min"
|
||||
public_ipv4_count = 0
|
||||
|
||||
@@ -55,6 +55,7 @@ func LoadBalancerResourceSchema(ctx context.Context) schema.Schema {
|
||||
Description: "Leave null to accept the default '/' path.",
|
||||
MarkdownDescription: "Leave null to accept the default '/' path.",
|
||||
Validators: []validator.String{
|
||||
stringvalidator.LengthAtLeast(1),
|
||||
stringvalidator.RegexMatches(regexp.MustCompile("/[A-Za-z0-9/.?=&+%_-]*"), ""),
|
||||
},
|
||||
},
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"context"
|
||||
"fmt"
|
||||
"slices"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework/attr"
|
||||
"github.com/hashicorp/terraform-plugin-framework/diag"
|
||||
"github.com/hashicorp/terraform-plugin-framework/path"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
)
|
||||
|
||||
// DiskKey identifies a disk across plans: the primary by being the primary, whose description
|
||||
// Binary Lane assigns, and every other disk by its description. Binary Lane allows two disks to
|
||||
// share a description, so they are also numbered within it: the second "data" disk configured is
|
||||
// the second "data" disk on the server.
|
||||
type DiskKey struct {
|
||||
primary bool
|
||||
description string
|
||||
ordinal int
|
||||
}
|
||||
|
||||
// DiskKeyer numbers disks as it keys them, so both sides of a match must be keyed in the same
|
||||
// order: id order for the server's own disks.
|
||||
type DiskKeyer map[string]int
|
||||
|
||||
func (k DiskKeyer) Of(primary bool, description string) DiskKey {
|
||||
if primary {
|
||||
return DiskKey{primary: true}
|
||||
}
|
||||
ordinal := k[description]
|
||||
k[description]++
|
||||
return DiskKey{description: description, ordinal: ordinal}
|
||||
}
|
||||
|
||||
// DiskShrinkWarning warns that shrinking a disk may corrupt the filesystem on it.
|
||||
func DiskShrinkWarning(attrPath path.Path, label string, from int64, to int64) diag.Diagnostic {
|
||||
return diag.NewAttributeWarningDiagnostic(
|
||||
attrPath,
|
||||
fmt.Sprintf("%s shrink may corrupt the filesystem", label),
|
||||
fmt.Sprintf(
|
||||
"%s is being reduced from %d GB to %d GB. Binary Lane resizes the block device in place and does not touch the "+
|
||||
"filesystem on it, so the filesystem(s) (and any partitions) on it must first be shrunk to fit within %d GB. "+
|
||||
"Back up the server before applying, and make sure there's enough free space to shrink the filesystem to that size.",
|
||||
label, from, to, to,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
// disksPlanModifier is referenced by name from the "disks" attribute in
|
||||
// scripts/data/server_disks.json, the same way disksValidator is.
|
||||
//
|
||||
// Terraform builds the proposed plan for a list by merging prior state into the configuration
|
||||
// element by element, so removing a disk hands the disks after it the id of their predecessor.
|
||||
// This plans the list from the configuration instead, taking each disk's server-assigned values
|
||||
// from the disk it matches in prior state rather than from whatever sits at the same index.
|
||||
type disksPlanModifier struct{}
|
||||
|
||||
func (m disksPlanModifier) Description(ctx context.Context) string {
|
||||
return "Matches each disk with the one it corresponds to in prior state, rather than with whatever is at the same index."
|
||||
}
|
||||
|
||||
func (m disksPlanModifier) MarkdownDescription(ctx context.Context) string {
|
||||
return m.Description(ctx)
|
||||
}
|
||||
|
||||
func (m disksPlanModifier) PlanModifyList(ctx context.Context, req planmodifier.ListRequest, resp *planmodifier.ListResponse) {
|
||||
// Nothing to plan when the resource is being destroyed.
|
||||
if req.Plan.Raw.IsNull() {
|
||||
return
|
||||
}
|
||||
|
||||
if req.ConfigValue.IsNull() || req.ConfigValue.IsUnknown() {
|
||||
// An unset `disks` is whatever Binary Lane gives the server, which isn't known until the
|
||||
// server exists. Once it does, the resource's ModifyPlan plans it instead: what happens
|
||||
// to the disks then depends on `disk`, the server's total, which it only resolves after
|
||||
// attribute plan modifiers like this one have run.
|
||||
if req.State.Raw.IsNull() {
|
||||
resp.PlanValue = types.ListUnknown(DisksValue{}.Type(ctx))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var configured, current []DisksValue
|
||||
resp.Diagnostics.Append(req.ConfigValue.ElementsAs(ctx, &configured, true)...)
|
||||
if !req.StateValue.IsNull() && !req.StateValue.IsUnknown() {
|
||||
resp.Diagnostics.Append(req.StateValue.ElementsAs(ctx, ¤t, true)...)
|
||||
}
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
// Key prior state in id order, the order the server's own disks are keyed in wherever they
|
||||
// are matched. serverDisksToList already leaves state in an order that agrees with it, but
|
||||
// this does not have to rely on that: get it wrong and disks that share a description are
|
||||
// paired with the wrong disk, and the plan promises a resize of one while the apply resizes
|
||||
// another.
|
||||
slices.SortStableFunc(current, func(a, b DisksValue) int {
|
||||
return cmp.Compare(a.Id.ValueInt64(), b.Id.ValueInt64())
|
||||
})
|
||||
|
||||
stateKeys := DiskKeyer{}
|
||||
priorByKey := make(map[DiskKey]DisksValue, len(current))
|
||||
for _, d := range current {
|
||||
priorByKey[stateKeys.Of(d.Primary.ValueBool(), d.Description.ValueString())] = d
|
||||
}
|
||||
|
||||
configKeys := DiskKeyer{}
|
||||
elements := make([]attr.Value, 0, len(configured))
|
||||
for _, cd := range configured {
|
||||
// Additional disks may leave `primary` unset, which means false.
|
||||
isPrimary := cd.Primary.ValueBool()
|
||||
prior, matched := priorByKey[configKeys.Of(isPrimary, cd.Description.ValueString())]
|
||||
|
||||
// `id` and the primary's `description` are assigned by Binary Lane, so both are unknown
|
||||
// until there is a disk in state to take them from.
|
||||
id, description := types.Int64Unknown(), cd.Description
|
||||
if isPrimary {
|
||||
description = types.StringUnknown()
|
||||
}
|
||||
if matched {
|
||||
if !prior.Id.IsNull() && !prior.Id.IsUnknown() {
|
||||
id = prior.Id
|
||||
}
|
||||
if isPrimary && !prior.Description.IsNull() && !prior.Description.IsUnknown() {
|
||||
description = prior.Description
|
||||
}
|
||||
if !cd.SizeGigabytes.IsUnknown() && cd.SizeGigabytes.ValueInt64() < prior.SizeGigabytes.ValueInt64() {
|
||||
label := fmt.Sprintf("Disk %q", cd.Description.ValueString())
|
||||
if isPrimary {
|
||||
label = "The primary disk"
|
||||
}
|
||||
resp.Diagnostics.Append(DiskShrinkWarning(
|
||||
req.Path, label, prior.SizeGigabytes.ValueInt64(), cd.SizeGigabytes.ValueInt64()))
|
||||
}
|
||||
}
|
||||
|
||||
disk, diskDiags := NewDisksValue(
|
||||
DisksValue{}.AttributeTypes(ctx),
|
||||
map[string]attr.Value{
|
||||
"id": id,
|
||||
"description": description,
|
||||
"primary": types.BoolValue(isPrimary),
|
||||
"size_gigabytes": cd.SizeGigabytes,
|
||||
},
|
||||
)
|
||||
resp.Diagnostics.Append(diskDiags...)
|
||||
elements = append(elements, disk)
|
||||
}
|
||||
|
||||
planned, diags := types.ListValue(DisksValue{}.Type(ctx), elements)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if !diags.HasError() {
|
||||
resp.PlanValue = planned
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework/path"
|
||||
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
)
|
||||
|
||||
// disksValidator is referenced by name from the "disks" attribute in
|
||||
// scripts/data/server_disks.json, which extend-provider.sh splices into the generated schema. It
|
||||
// lives here rather than in internal/provider, which internal/resources cannot import.
|
||||
type disksValidator struct{}
|
||||
|
||||
func (v disksValidator) Description(ctx context.Context) string {
|
||||
return "Requires exactly one `disks` entry to have `primary = true` (with no `description` set) whenever `disks` is configured, and `sum(disks[*].size_gigabytes)` to not exceed `disk`."
|
||||
}
|
||||
|
||||
func (v disksValidator) MarkdownDescription(ctx context.Context) string {
|
||||
return v.Description(ctx)
|
||||
}
|
||||
|
||||
func (v disksValidator) ValidateList(ctx context.Context, req validator.ListRequest, resp *validator.ListResponse) {
|
||||
if req.ConfigValue.IsNull() || req.ConfigValue.IsUnknown() {
|
||||
return
|
||||
}
|
||||
|
||||
var disks []DisksValue
|
||||
resp.Diagnostics.Append(req.ConfigValue.ElementsAs(ctx, &disks, false)...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
primaries, primaryUnknown := 0, false
|
||||
sum, sumKnown := int64(0), true
|
||||
for i, d := range disks {
|
||||
switch {
|
||||
case d.Primary.IsUnknown():
|
||||
primaryUnknown = true
|
||||
case d.Primary.ValueBool():
|
||||
primaries++
|
||||
if !d.Description.IsNull() && !d.Description.IsUnknown() {
|
||||
resp.Diagnostics.AddAttributeError(
|
||||
req.Path.AtListIndex(i).AtName("description"),
|
||||
"Primary disk description is server-assigned",
|
||||
"The primary disk's `description` is always assigned by Binary Lane (typically \"SYSTEM\"); leave it unset on the entry with `primary = true`.",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if d.SizeGigabytes.IsNull() || d.SizeGigabytes.IsUnknown() {
|
||||
sumKnown = false
|
||||
continue
|
||||
}
|
||||
sum += d.SizeGigabytes.ValueInt64()
|
||||
}
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
if !primaryUnknown {
|
||||
if primaries == 0 {
|
||||
resp.Diagnostics.AddAttributeError(
|
||||
req.Path,
|
||||
"Missing primary disk",
|
||||
"When `disks` is specified, it must fully describe every disk, including the primary — add an entry with `primary = true`.",
|
||||
)
|
||||
return
|
||||
}
|
||||
if primaries > 1 {
|
||||
resp.Diagnostics.AddAttributeError(
|
||||
req.Path,
|
||||
"Multiple primary disks",
|
||||
"Only one entry in `disks` can have `primary = true`.",
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var disk types.Int32
|
||||
resp.Diagnostics.Append(req.Config.GetAttribute(ctx, path.Root("disk"), &disk)...)
|
||||
if resp.Diagnostics.HasError() || !sumKnown || disk.IsNull() || disk.IsUnknown() {
|
||||
return
|
||||
}
|
||||
if sum > int64(disk.ValueInt32()) {
|
||||
resp.Diagnostics.AddAttributeError(
|
||||
req.Path,
|
||||
"Disks exceed total disk allocation",
|
||||
fmt.Sprintf(
|
||||
"The sum of `disks[*].size_gigabytes` is %d GB, which exceeds `disk` (%d GB total). "+
|
||||
"`sum(disks[*].size_gigabytes)` must not exceed `disk`.",
|
||||
sum, disk.ValueInt32(),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,11 @@ package resources
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
|
||||
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
|
||||
"github.com/hashicorp/terraform-plugin-framework/attr"
|
||||
"github.com/hashicorp/terraform-plugin-framework/diag"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
|
||||
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
|
||||
@@ -94,6 +96,55 @@ func ServerResourceSchema(ctx context.Context) schema.Schema {
|
||||
Description: "If true this will enable two daily backups for the server. `options.daily_backups` will override this value if provided. Setting this to false has no effect.\n",
|
||||
MarkdownDescription: "If true this will enable two daily backups for the server. `options.daily_backups` will override this value if provided. Setting this to false has no effect.\n",
|
||||
},
|
||||
"disks": schema.ListNestedAttribute{
|
||||
NestedObject: schema.NestedAttributeObject{
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"description": schema.StringAttribute{
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
Description: "A label for this disk. Assigned by Binary Lane for the primary disk, so must be left null when `primary = true`. Changing this will destroy the disk and create a new one, losing any data on it. Disks that share a description are matched in the order they are listed.",
|
||||
MarkdownDescription: "A label for this disk. Assigned by Binary Lane for the primary disk, so must be left null when `primary = true`. Changing this will destroy the disk and create a new one, losing any data on it. Disks that share a description are matched in the order they are listed.",
|
||||
Validators: []validator.String{
|
||||
stringvalidator.LengthAtLeast(1),
|
||||
},
|
||||
},
|
||||
"id": schema.Int64Attribute{
|
||||
Computed: true,
|
||||
Description: "The ID of this disk.",
|
||||
MarkdownDescription: "The ID of this disk.",
|
||||
},
|
||||
"primary": schema.BoolAttribute{
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
Description: "If `true` this is the primary disk, which the operating system is installed on. Exactly one disk must be the primary.",
|
||||
MarkdownDescription: "If `true` this is the primary disk, which the operating system is installed on. Exactly one disk must be the primary.",
|
||||
},
|
||||
"size_gigabytes": schema.Int64Attribute{
|
||||
Required: true,
|
||||
Description: "The size of the disk in GB. The sum across all disks cannot exceed `disk`, and any remainder is left unallocated.",
|
||||
MarkdownDescription: "The size of the disk in GB. The sum across all disks cannot exceed `disk`, and any remainder is left unallocated.",
|
||||
Validators: []validator.Int64{
|
||||
int64validator.AtLeast(1),
|
||||
},
|
||||
},
|
||||
},
|
||||
CustomType: DisksType{
|
||||
ObjectType: types.ObjectType{
|
||||
AttrTypes: DisksValue{}.AttributeTypes(ctx),
|
||||
},
|
||||
},
|
||||
},
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
Description: "The disks attached to this server. Leave null to let Binary Lane manage the server's disks. If specified, every disk must be listed, including the primary: exactly one entry must have `primary = true`, and its `id` and `description` are assigned by Binary Lane.",
|
||||
MarkdownDescription: "The disks attached to this server. Leave null to let Binary Lane manage the server's disks. If specified, every disk must be listed, including the primary: exactly one entry must have `primary = true`, and its `id` and `description` are assigned by Binary Lane.",
|
||||
PlanModifiers: []planmodifier.List{
|
||||
disksPlanModifier{},
|
||||
},
|
||||
Validators: []validator.List{
|
||||
disksValidator{},
|
||||
},
|
||||
},
|
||||
"id": schema.Int64Attribute{
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
@@ -120,8 +171,8 @@ func ServerResourceSchema(ctx context.Context) schema.Schema {
|
||||
"port_blocking": schema.BoolAttribute{
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
Description: "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.",
|
||||
MarkdownDescription: "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.",
|
||||
Description: "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 verified accounts.",
|
||||
MarkdownDescription: "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 verified accounts.",
|
||||
},
|
||||
"region": schema.StringAttribute{
|
||||
Required: true,
|
||||
@@ -131,6 +182,12 @@ func ServerResourceSchema(ctx context.Context) schema.Schema {
|
||||
stringvalidator.LengthAtLeast(1),
|
||||
},
|
||||
},
|
||||
"separate_private_network_interface": schema.BoolAttribute{
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
Description: "If true this will enable a separate private network interface for the server. This is only available for servers in a VPC.",
|
||||
MarkdownDescription: "If true this will enable a separate private network interface for the server. This is only available for servers in a VPC.",
|
||||
},
|
||||
"size": schema.StringAttribute{
|
||||
Required: true,
|
||||
Description: "The slug of the selected size.",
|
||||
@@ -172,19 +229,21 @@ func ServerResourceSchema(ctx context.Context) schema.Schema {
|
||||
}
|
||||
|
||||
type ServerModel struct {
|
||||
AdvancedFeatures AdvancedFeaturesValue `tfsdk:"advanced_features"`
|
||||
Backups types.Bool `tfsdk:"backups"`
|
||||
Id types.Int64 `tfsdk:"id"`
|
||||
Image types.String `tfsdk:"image"`
|
||||
Ipv6 types.Bool `tfsdk:"ipv6"`
|
||||
Name types.String `tfsdk:"name"`
|
||||
PortBlocking types.Bool `tfsdk:"port_blocking"`
|
||||
Region types.String `tfsdk:"region"`
|
||||
Size types.String `tfsdk:"size"`
|
||||
SshKeys types.List `tfsdk:"ssh_keys"`
|
||||
UserData types.String `tfsdk:"user_data"`
|
||||
VpcId types.Int64 `tfsdk:"vpc_id"`
|
||||
VpcIpv4Address types.String `tfsdk:"vpc_ipv4_address"`
|
||||
AdvancedFeatures AdvancedFeaturesValue `tfsdk:"advanced_features"`
|
||||
Backups types.Bool `tfsdk:"backups"`
|
||||
Disks types.List `tfsdk:"disks"`
|
||||
Id types.Int64 `tfsdk:"id"`
|
||||
Image types.String `tfsdk:"image"`
|
||||
Ipv6 types.Bool `tfsdk:"ipv6"`
|
||||
Name types.String `tfsdk:"name"`
|
||||
PortBlocking types.Bool `tfsdk:"port_blocking"`
|
||||
Region types.String `tfsdk:"region"`
|
||||
SeparatePrivateNetworkInterface types.Bool `tfsdk:"separate_private_network_interface"`
|
||||
Size types.String `tfsdk:"size"`
|
||||
SshKeys types.List `tfsdk:"ssh_keys"`
|
||||
UserData types.String `tfsdk:"user_data"`
|
||||
VpcId types.Int64 `tfsdk:"vpc_id"`
|
||||
VpcIpv4Address types.String `tfsdk:"vpc_ipv4_address"`
|
||||
}
|
||||
|
||||
var _ basetypes.ObjectTypable = AdvancedFeaturesType{}
|
||||
@@ -1005,3 +1064,492 @@ func (v AdvancedFeaturesValue) AttributeTypes(ctx context.Context) map[string]at
|
||||
"unset_uuid": basetypes.BoolType{},
|
||||
}
|
||||
}
|
||||
|
||||
var _ basetypes.ObjectTypable = DisksType{}
|
||||
|
||||
type DisksType struct {
|
||||
basetypes.ObjectType
|
||||
}
|
||||
|
||||
func (t DisksType) Equal(o attr.Type) bool {
|
||||
other, ok := o.(DisksType)
|
||||
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
return t.ObjectType.Equal(other.ObjectType)
|
||||
}
|
||||
|
||||
func (t DisksType) String() string {
|
||||
return "DisksType"
|
||||
}
|
||||
|
||||
func (t DisksType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) {
|
||||
var diags diag.Diagnostics
|
||||
|
||||
attributes := in.Attributes()
|
||||
|
||||
descriptionAttribute, ok := attributes["description"]
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Missing",
|
||||
`description is missing from object`)
|
||||
|
||||
return nil, diags
|
||||
}
|
||||
|
||||
descriptionVal, ok := descriptionAttribute.(basetypes.StringValue)
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Wrong Type",
|
||||
fmt.Sprintf(`description expected to be basetypes.StringValue, was: %T`, descriptionAttribute))
|
||||
}
|
||||
|
||||
idAttribute, ok := attributes["id"]
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Missing",
|
||||
`id is missing from object`)
|
||||
|
||||
return nil, diags
|
||||
}
|
||||
|
||||
idVal, ok := idAttribute.(basetypes.Int64Value)
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Wrong Type",
|
||||
fmt.Sprintf(`id expected to be basetypes.Int64Value, was: %T`, idAttribute))
|
||||
}
|
||||
|
||||
primaryAttribute, ok := attributes["primary"]
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Missing",
|
||||
`primary is missing from object`)
|
||||
|
||||
return nil, diags
|
||||
}
|
||||
|
||||
primaryVal, ok := primaryAttribute.(basetypes.BoolValue)
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Wrong Type",
|
||||
fmt.Sprintf(`primary expected to be basetypes.BoolValue, was: %T`, primaryAttribute))
|
||||
}
|
||||
|
||||
sizeGigabytesAttribute, ok := attributes["size_gigabytes"]
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Missing",
|
||||
`size_gigabytes is missing from object`)
|
||||
|
||||
return nil, diags
|
||||
}
|
||||
|
||||
sizeGigabytesVal, ok := sizeGigabytesAttribute.(basetypes.Int64Value)
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Wrong Type",
|
||||
fmt.Sprintf(`size_gigabytes expected to be basetypes.Int64Value, was: %T`, sizeGigabytesAttribute))
|
||||
}
|
||||
|
||||
if diags.HasError() {
|
||||
return nil, diags
|
||||
}
|
||||
|
||||
return DisksValue{
|
||||
Description: descriptionVal,
|
||||
Id: idVal,
|
||||
Primary: primaryVal,
|
||||
SizeGigabytes: sizeGigabytesVal,
|
||||
state: attr.ValueStateKnown,
|
||||
}, diags
|
||||
}
|
||||
|
||||
func NewDisksValueNull() DisksValue {
|
||||
return DisksValue{
|
||||
state: attr.ValueStateNull,
|
||||
}
|
||||
}
|
||||
|
||||
func NewDisksValueUnknown() DisksValue {
|
||||
return DisksValue{
|
||||
state: attr.ValueStateUnknown,
|
||||
}
|
||||
}
|
||||
|
||||
func NewDisksValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (DisksValue, diag.Diagnostics) {
|
||||
var diags diag.Diagnostics
|
||||
|
||||
// Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521
|
||||
ctx := context.Background()
|
||||
|
||||
for name, attributeType := range attributeTypes {
|
||||
attribute, ok := attributes[name]
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Missing DisksValue Attribute Value",
|
||||
"While creating a DisksValue value, a missing attribute value was detected. "+
|
||||
"A DisksValue must contain values for all attributes, even if null or unknown. "+
|
||||
"This is always an issue with the provider and should be reported to the provider developers.\n\n"+
|
||||
fmt.Sprintf("DisksValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()),
|
||||
)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if !attributeType.Equal(attribute.Type(ctx)) {
|
||||
diags.AddError(
|
||||
"Invalid DisksValue Attribute Type",
|
||||
"While creating a DisksValue value, an invalid attribute value was detected. "+
|
||||
"A DisksValue must use a matching attribute type for the value. "+
|
||||
"This is always an issue with the provider and should be reported to the provider developers.\n\n"+
|
||||
fmt.Sprintf("DisksValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+
|
||||
fmt.Sprintf("DisksValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
for name := range attributes {
|
||||
_, ok := attributeTypes[name]
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Extra DisksValue Attribute Value",
|
||||
"While creating a DisksValue value, an extra attribute value was detected. "+
|
||||
"A DisksValue must not contain values beyond the expected attribute types. "+
|
||||
"This is always an issue with the provider and should be reported to the provider developers.\n\n"+
|
||||
fmt.Sprintf("Extra DisksValue Attribute Name: %s", name),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if diags.HasError() {
|
||||
return NewDisksValueUnknown(), diags
|
||||
}
|
||||
|
||||
descriptionAttribute, ok := attributes["description"]
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Missing",
|
||||
`description is missing from object`)
|
||||
|
||||
return NewDisksValueUnknown(), diags
|
||||
}
|
||||
|
||||
descriptionVal, ok := descriptionAttribute.(basetypes.StringValue)
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Wrong Type",
|
||||
fmt.Sprintf(`description expected to be basetypes.StringValue, was: %T`, descriptionAttribute))
|
||||
}
|
||||
|
||||
idAttribute, ok := attributes["id"]
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Missing",
|
||||
`id is missing from object`)
|
||||
|
||||
return NewDisksValueUnknown(), diags
|
||||
}
|
||||
|
||||
idVal, ok := idAttribute.(basetypes.Int64Value)
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Wrong Type",
|
||||
fmt.Sprintf(`id expected to be basetypes.Int64Value, was: %T`, idAttribute))
|
||||
}
|
||||
|
||||
primaryAttribute, ok := attributes["primary"]
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Missing",
|
||||
`primary is missing from object`)
|
||||
|
||||
return NewDisksValueUnknown(), diags
|
||||
}
|
||||
|
||||
primaryVal, ok := primaryAttribute.(basetypes.BoolValue)
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Wrong Type",
|
||||
fmt.Sprintf(`primary expected to be basetypes.BoolValue, was: %T`, primaryAttribute))
|
||||
}
|
||||
|
||||
sizeGigabytesAttribute, ok := attributes["size_gigabytes"]
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Missing",
|
||||
`size_gigabytes is missing from object`)
|
||||
|
||||
return NewDisksValueUnknown(), diags
|
||||
}
|
||||
|
||||
sizeGigabytesVal, ok := sizeGigabytesAttribute.(basetypes.Int64Value)
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Wrong Type",
|
||||
fmt.Sprintf(`size_gigabytes expected to be basetypes.Int64Value, was: %T`, sizeGigabytesAttribute))
|
||||
}
|
||||
|
||||
if diags.HasError() {
|
||||
return NewDisksValueUnknown(), diags
|
||||
}
|
||||
|
||||
return DisksValue{
|
||||
Description: descriptionVal,
|
||||
Id: idVal,
|
||||
Primary: primaryVal,
|
||||
SizeGigabytes: sizeGigabytesVal,
|
||||
state: attr.ValueStateKnown,
|
||||
}, diags
|
||||
}
|
||||
|
||||
func NewDisksValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) DisksValue {
|
||||
object, diags := NewDisksValue(attributeTypes, attributes)
|
||||
|
||||
if diags.HasError() {
|
||||
// This could potentially be added to the diag package.
|
||||
diagsStrings := make([]string, 0, len(diags))
|
||||
|
||||
for _, diagnostic := range diags {
|
||||
diagsStrings = append(diagsStrings, fmt.Sprintf(
|
||||
"%s | %s | %s",
|
||||
diagnostic.Severity(),
|
||||
diagnostic.Summary(),
|
||||
diagnostic.Detail()))
|
||||
}
|
||||
|
||||
panic("NewDisksValueMust received error(s): " + strings.Join(diagsStrings, "\n"))
|
||||
}
|
||||
|
||||
return object
|
||||
}
|
||||
|
||||
func (t DisksType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) {
|
||||
if in.Type() == nil {
|
||||
return NewDisksValueNull(), nil
|
||||
}
|
||||
|
||||
if !in.Type().Equal(t.TerraformType(ctx)) {
|
||||
return nil, fmt.Errorf("expected %s, got %s", t.TerraformType(ctx), in.Type())
|
||||
}
|
||||
|
||||
if !in.IsKnown() {
|
||||
return NewDisksValueUnknown(), nil
|
||||
}
|
||||
|
||||
if in.IsNull() {
|
||||
return NewDisksValueNull(), nil
|
||||
}
|
||||
|
||||
attributes := map[string]attr.Value{}
|
||||
|
||||
val := map[string]tftypes.Value{}
|
||||
|
||||
err := in.As(&val)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for k, v := range val {
|
||||
a, err := t.AttrTypes[k].ValueFromTerraform(ctx, v)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
attributes[k] = a
|
||||
}
|
||||
|
||||
return NewDisksValueMust(DisksValue{}.AttributeTypes(ctx), attributes), nil
|
||||
}
|
||||
|
||||
func (t DisksType) ValueType(ctx context.Context) attr.Value {
|
||||
return DisksValue{}
|
||||
}
|
||||
|
||||
var _ basetypes.ObjectValuable = DisksValue{}
|
||||
|
||||
type DisksValue struct {
|
||||
Description basetypes.StringValue `tfsdk:"description"`
|
||||
Id basetypes.Int64Value `tfsdk:"id"`
|
||||
Primary basetypes.BoolValue `tfsdk:"primary"`
|
||||
SizeGigabytes basetypes.Int64Value `tfsdk:"size_gigabytes"`
|
||||
state attr.ValueState
|
||||
}
|
||||
|
||||
func (v DisksValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) {
|
||||
attrTypes := make(map[string]tftypes.Type, 4)
|
||||
|
||||
var val tftypes.Value
|
||||
var err error
|
||||
|
||||
attrTypes["description"] = basetypes.StringType{}.TerraformType(ctx)
|
||||
attrTypes["id"] = basetypes.Int64Type{}.TerraformType(ctx)
|
||||
attrTypes["primary"] = basetypes.BoolType{}.TerraformType(ctx)
|
||||
attrTypes["size_gigabytes"] = basetypes.Int64Type{}.TerraformType(ctx)
|
||||
|
||||
objectType := tftypes.Object{AttributeTypes: attrTypes}
|
||||
|
||||
switch v.state {
|
||||
case attr.ValueStateKnown:
|
||||
vals := make(map[string]tftypes.Value, 4)
|
||||
|
||||
val, err = v.Description.ToTerraformValue(ctx)
|
||||
|
||||
if err != nil {
|
||||
return tftypes.NewValue(objectType, tftypes.UnknownValue), err
|
||||
}
|
||||
|
||||
vals["description"] = val
|
||||
|
||||
val, err = v.Id.ToTerraformValue(ctx)
|
||||
|
||||
if err != nil {
|
||||
return tftypes.NewValue(objectType, tftypes.UnknownValue), err
|
||||
}
|
||||
|
||||
vals["id"] = val
|
||||
|
||||
val, err = v.Primary.ToTerraformValue(ctx)
|
||||
|
||||
if err != nil {
|
||||
return tftypes.NewValue(objectType, tftypes.UnknownValue), err
|
||||
}
|
||||
|
||||
vals["primary"] = val
|
||||
|
||||
val, err = v.SizeGigabytes.ToTerraformValue(ctx)
|
||||
|
||||
if err != nil {
|
||||
return tftypes.NewValue(objectType, tftypes.UnknownValue), err
|
||||
}
|
||||
|
||||
vals["size_gigabytes"] = val
|
||||
|
||||
if err := tftypes.ValidateValue(objectType, vals); err != nil {
|
||||
return tftypes.NewValue(objectType, tftypes.UnknownValue), err
|
||||
}
|
||||
|
||||
return tftypes.NewValue(objectType, vals), nil
|
||||
case attr.ValueStateNull:
|
||||
return tftypes.NewValue(objectType, nil), nil
|
||||
case attr.ValueStateUnknown:
|
||||
return tftypes.NewValue(objectType, tftypes.UnknownValue), nil
|
||||
default:
|
||||
panic(fmt.Sprintf("unhandled Object state in ToTerraformValue: %s", v.state))
|
||||
}
|
||||
}
|
||||
|
||||
func (v DisksValue) IsNull() bool {
|
||||
return v.state == attr.ValueStateNull
|
||||
}
|
||||
|
||||
func (v DisksValue) IsUnknown() bool {
|
||||
return v.state == attr.ValueStateUnknown
|
||||
}
|
||||
|
||||
func (v DisksValue) String() string {
|
||||
return "DisksValue"
|
||||
}
|
||||
|
||||
func (v DisksValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) {
|
||||
var diags diag.Diagnostics
|
||||
|
||||
attributeTypes := map[string]attr.Type{
|
||||
"description": basetypes.StringType{},
|
||||
"id": basetypes.Int64Type{},
|
||||
"primary": basetypes.BoolType{},
|
||||
"size_gigabytes": basetypes.Int64Type{},
|
||||
}
|
||||
|
||||
if v.IsNull() {
|
||||
return types.ObjectNull(attributeTypes), diags
|
||||
}
|
||||
|
||||
if v.IsUnknown() {
|
||||
return types.ObjectUnknown(attributeTypes), diags
|
||||
}
|
||||
|
||||
objVal, diags := types.ObjectValue(
|
||||
attributeTypes,
|
||||
map[string]attr.Value{
|
||||
"description": v.Description,
|
||||
"id": v.Id,
|
||||
"primary": v.Primary,
|
||||
"size_gigabytes": v.SizeGigabytes,
|
||||
})
|
||||
|
||||
return objVal, diags
|
||||
}
|
||||
|
||||
func (v DisksValue) Equal(o attr.Value) bool {
|
||||
other, ok := o.(DisksValue)
|
||||
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
if v.state != other.state {
|
||||
return false
|
||||
}
|
||||
|
||||
if v.state != attr.ValueStateKnown {
|
||||
return true
|
||||
}
|
||||
|
||||
if !v.Description.Equal(other.Description) {
|
||||
return false
|
||||
}
|
||||
|
||||
if !v.Id.Equal(other.Id) {
|
||||
return false
|
||||
}
|
||||
|
||||
if !v.Primary.Equal(other.Primary) {
|
||||
return false
|
||||
}
|
||||
|
||||
if !v.SizeGigabytes.Equal(other.SizeGigabytes) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (v DisksValue) Type(ctx context.Context) attr.Type {
|
||||
return DisksType{
|
||||
basetypes.ObjectType{
|
||||
AttrTypes: v.AttributeTypes(ctx),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (v DisksValue) AttributeTypes(ctx context.Context) map[string]attr.Type {
|
||||
return map[string]attr.Type{
|
||||
"description": basetypes.StringType{},
|
||||
"id": basetypes.Int64Type{},
|
||||
"primary": basetypes.BoolType{},
|
||||
"size_gigabytes": basetypes.Int64Type{},
|
||||
}
|
||||
}
|
||||
|
||||
+140
-85
@@ -2,13 +2,13 @@
|
||||
"openapi": "3.0.4",
|
||||
"info": {
|
||||
"title": "BinaryLane API",
|
||||
"description": "# Introduction\n\nThis API is used by BinaryLane's 'mPanel' website, so you'll find everything you need here to automate your use of BinaryLane or develop tools for others. You could even build your own version of 'mPanel' if you wanted!\n\n\n## Getting Started Guide\n\nYou can find a detailed guide to using the API to manage your servers <a href='https://support.binarylane.com.au/support/solutions/articles/11000125203-getting-started-with-binarylane-api' target='_blank' rel='noopener noreferrer'>here</a>.\n\n\n# API Tools\n\nWe have created a CLI tool to interact with the API. You can find the repository <a href='https://github.com/binarylane/binarylane-cli' target='_blank' rel='noopener noreferrer'>here</a>.\n\n\n# Developer Preview Notes\n\n**Warning: this specification is currently in active development.** Until this warning is removed breaking changes are possible without the version changing.\nHowever, this API is mature and we have a fully functioning new version of mPanel that uses it, so breaking changes will be very limited.\n\nWe welcome all feedback from API users at the support email address above.\n\n\n# Version Information\n\nThis section will contain a link to our changelog once the developer preview period is complete.",
|
||||
"description": "# Introduction\n\nThis API is used by BinaryLane's 'mPanel' website, so you'll find everything you need here to automate your use of BinaryLane or develop tools for others. You could even build your own version of 'mPanel' if you wanted!\n\n\n## Getting Started Guide\n\nYou can find a detailed guide to using the API to manage your servers <a href='https://support.binarylane.com.au/support/solutions/articles/11000125203-getting-started-with-binarylane-api' target='_blank' rel='noopener noreferrer'>here</a>.\n\n\n# API Tools\n\nWe have created a CLI tool to interact with the API. You can find the repository <a href='https://github.com/binarylane/binarylane-cli' target='_blank' rel='noopener noreferrer'>here</a>.\n\n\n# Units\n\nStorage, memory and data-transfer values use the familiar `GB`, `MB` and `TB` labels (matching our control panel and website) rather than the IEC `GiB`/`MiB` forms. The exact byte conventions are:\n\n| Label | Used for | Definition |\n| --- | --- | --- |\n| `MB` | Memory, storage | Binary megabyte: 1 MB = 1024² bytes |\n| `GB` | Disk, storage, data transfer | Binary gigabyte: 1 GB = 1024³ bytes |\n| `TB` | Data transfer | 1 TB = 1000 GB, where each GB = 1024³ bytes (so 1 TB = 1000 × 1024³ bytes) |\n\n\n# Developer Preview Notes\n\n**Warning: this specification is currently in active development.** Until this warning is removed breaking changes are possible without the version changing.\nHowever, this API is mature and we have a fully functioning new version of mPanel that uses it, so breaking changes will be very limited.\n\nWe welcome all feedback from API users at the support email address above.\n\n\n# Version Information\n\nThis section will contain a link to our changelog once the developer preview period is complete.",
|
||||
"contact": {
|
||||
"name": "BinaryLane Support",
|
||||
"url": "https://support.binarylane.com.au/support/home",
|
||||
"email": "support@binarylane.com.au"
|
||||
},
|
||||
"version": "0.35.1",
|
||||
"version": "0.40.0",
|
||||
"x-logo": {
|
||||
"url": "https://www.binarylane.com.au/res/images/binarylane/logo.png",
|
||||
"backgroundColor": "#000000",
|
||||
@@ -111,12 +111,12 @@
|
||||
{
|
||||
"name": "per_page",
|
||||
"in": "query",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"schema": {
|
||||
"maximum": 200,
|
||||
"minimum": 1,
|
||||
"minimum": 0,
|
||||
"type": "integer",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"format": "int32",
|
||||
"default": 20
|
||||
}
|
||||
@@ -277,12 +277,12 @@
|
||||
{
|
||||
"name": "per_page",
|
||||
"in": "query",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"schema": {
|
||||
"maximum": 200,
|
||||
"minimum": 1,
|
||||
"minimum": 0,
|
||||
"type": "integer",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"format": "int32",
|
||||
"default": 20
|
||||
}
|
||||
@@ -401,12 +401,12 @@
|
||||
{
|
||||
"name": "per_page",
|
||||
"in": "query",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"schema": {
|
||||
"maximum": 200,
|
||||
"minimum": 1,
|
||||
"minimum": 0,
|
||||
"type": "integer",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"format": "int32",
|
||||
"default": 20
|
||||
}
|
||||
@@ -517,12 +517,12 @@
|
||||
{
|
||||
"name": "per_page",
|
||||
"in": "query",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"schema": {
|
||||
"maximum": 200,
|
||||
"minimum": 1,
|
||||
"minimum": 0,
|
||||
"type": "integer",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"format": "int32",
|
||||
"default": 20
|
||||
}
|
||||
@@ -730,12 +730,12 @@
|
||||
{
|
||||
"name": "per_page",
|
||||
"in": "query",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"schema": {
|
||||
"maximum": 200,
|
||||
"minimum": 1,
|
||||
"minimum": 0,
|
||||
"type": "integer",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"format": "int32",
|
||||
"default": 20
|
||||
}
|
||||
@@ -1029,12 +1029,12 @@
|
||||
{
|
||||
"name": "per_page",
|
||||
"in": "query",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"schema": {
|
||||
"maximum": 200,
|
||||
"minimum": 1,
|
||||
"minimum": 0,
|
||||
"type": "integer",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"format": "int32",
|
||||
"default": 20
|
||||
}
|
||||
@@ -1292,12 +1292,12 @@
|
||||
{
|
||||
"name": "per_page",
|
||||
"in": "query",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"schema": {
|
||||
"maximum": 200,
|
||||
"minimum": 1,
|
||||
"minimum": 0,
|
||||
"type": "integer",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"format": "int32",
|
||||
"default": 20
|
||||
}
|
||||
@@ -1492,6 +1492,14 @@
|
||||
],
|
||||
"summary": "List all Load Balancers",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "name",
|
||||
"in": "query",
|
||||
"description": "Providing a name restricts the results to load balancers with this name (case insensitive).",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "page",
|
||||
"in": "query",
|
||||
@@ -1508,12 +1516,12 @@
|
||||
{
|
||||
"name": "per_page",
|
||||
"in": "query",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"schema": {
|
||||
"maximum": 200,
|
||||
"minimum": 1,
|
||||
"minimum": 0,
|
||||
"type": "integer",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"format": "int32",
|
||||
"default": 20
|
||||
}
|
||||
@@ -1534,7 +1542,7 @@
|
||||
"x-codeSamples": [
|
||||
{
|
||||
"lang": "Curl",
|
||||
"source": "curl -X GET \"https://api.binarylane.com.au/v2/load_balancers?page=${page}&per_page=${per_page}\" \\\n-H \"Authorization: Bearer ${APITOKEN}\""
|
||||
"source": "curl -X GET \"https://api.binarylane.com.au/v2/load_balancers?name=${name}&page=${page}&per_page=${per_page}\" \\\n-H \"Authorization: Bearer ${APITOKEN}\""
|
||||
}
|
||||
],
|
||||
"x-cli-command": "load-balancer list"
|
||||
@@ -1808,12 +1816,12 @@
|
||||
{
|
||||
"name": "per_page",
|
||||
"in": "query",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"schema": {
|
||||
"maximum": 200,
|
||||
"minimum": 1,
|
||||
"minimum": 0,
|
||||
"type": "integer",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"format": "int32",
|
||||
"default": 20
|
||||
}
|
||||
@@ -1864,12 +1872,12 @@
|
||||
{
|
||||
"name": "per_page",
|
||||
"in": "query",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"schema": {
|
||||
"maximum": 200,
|
||||
"minimum": 1,
|
||||
"minimum": 0,
|
||||
"type": "integer",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"format": "int32",
|
||||
"default": 20
|
||||
}
|
||||
@@ -2056,12 +2064,12 @@
|
||||
{
|
||||
"name": "per_page",
|
||||
"in": "query",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"schema": {
|
||||
"maximum": 200,
|
||||
"minimum": 1,
|
||||
"minimum": 0,
|
||||
"type": "integer",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"format": "int32",
|
||||
"default": 20
|
||||
}
|
||||
@@ -2122,12 +2130,12 @@
|
||||
{
|
||||
"name": "per_page",
|
||||
"in": "query",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"schema": {
|
||||
"maximum": 200,
|
||||
"minimum": 1,
|
||||
"minimum": 0,
|
||||
"type": "integer",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"format": "int32",
|
||||
"default": 20
|
||||
}
|
||||
@@ -2495,12 +2503,12 @@
|
||||
{
|
||||
"name": "per_page",
|
||||
"in": "query",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"schema": {
|
||||
"maximum": 200,
|
||||
"minimum": 1,
|
||||
"minimum": 0,
|
||||
"type": "integer",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"format": "int32",
|
||||
"default": 20
|
||||
}
|
||||
@@ -2729,12 +2737,12 @@
|
||||
{
|
||||
"name": "per_page",
|
||||
"in": "query",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"schema": {
|
||||
"maximum": 200,
|
||||
"minimum": 1,
|
||||
"minimum": 0,
|
||||
"type": "integer",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"format": "int32",
|
||||
"default": 20
|
||||
}
|
||||
@@ -2847,12 +2855,12 @@
|
||||
{
|
||||
"name": "per_page",
|
||||
"in": "query",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"schema": {
|
||||
"maximum": 200,
|
||||
"minimum": 1,
|
||||
"minimum": 0,
|
||||
"type": "integer",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"format": "int32",
|
||||
"default": 20
|
||||
}
|
||||
@@ -2914,12 +2922,12 @@
|
||||
{
|
||||
"name": "per_page",
|
||||
"in": "query",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"schema": {
|
||||
"maximum": 200,
|
||||
"minimum": 1,
|
||||
"minimum": 0,
|
||||
"type": "integer",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"format": "int32",
|
||||
"default": 20
|
||||
}
|
||||
@@ -3048,12 +3056,12 @@
|
||||
{
|
||||
"name": "per_page",
|
||||
"in": "query",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"schema": {
|
||||
"maximum": 200,
|
||||
"minimum": 1,
|
||||
"minimum": 0,
|
||||
"type": "integer",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"format": "int32",
|
||||
"default": 20
|
||||
}
|
||||
@@ -3201,12 +3209,12 @@
|
||||
{
|
||||
"name": "per_page",
|
||||
"in": "query",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"schema": {
|
||||
"maximum": 200,
|
||||
"minimum": 1,
|
||||
"minimum": 0,
|
||||
"type": "integer",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"format": "int32",
|
||||
"default": 20
|
||||
}
|
||||
@@ -3295,12 +3303,12 @@
|
||||
{
|
||||
"name": "per_page",
|
||||
"in": "query",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"schema": {
|
||||
"maximum": 200,
|
||||
"minimum": 1,
|
||||
"minimum": 0,
|
||||
"type": "integer",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"format": "int32",
|
||||
"default": 20
|
||||
}
|
||||
@@ -3368,12 +3376,12 @@
|
||||
{
|
||||
"name": "per_page",
|
||||
"in": "query",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"schema": {
|
||||
"maximum": 200,
|
||||
"minimum": 1,
|
||||
"minimum": 0,
|
||||
"type": "integer",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"format": "int32",
|
||||
"default": 20
|
||||
}
|
||||
@@ -3603,12 +3611,12 @@
|
||||
{
|
||||
"name": "per_page",
|
||||
"in": "query",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"schema": {
|
||||
"maximum": 200,
|
||||
"minimum": 1,
|
||||
"minimum": 0,
|
||||
"type": "integer",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"format": "int32",
|
||||
"default": 20
|
||||
}
|
||||
@@ -3721,12 +3729,12 @@
|
||||
{
|
||||
"name": "per_page",
|
||||
"in": "query",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"schema": {
|
||||
"maximum": 200,
|
||||
"minimum": 1,
|
||||
"minimum": 0,
|
||||
"type": "integer",
|
||||
"description": "The number of results to show per page.",
|
||||
"description": "The number of results to show per page. Use 0 to return only the total count.",
|
||||
"format": "int32",
|
||||
"default": 20
|
||||
}
|
||||
@@ -6000,7 +6008,7 @@
|
||||
},
|
||||
"email_verified": {
|
||||
"type": "boolean",
|
||||
"description": "Whether this account has been verified. Un-verified accounts are subject to some restrictions."
|
||||
"description": "Whether this account has been verified. Unverified accounts are subject to some restrictions."
|
||||
},
|
||||
"two_factor_authentication_enabled": {
|
||||
"type": "boolean",
|
||||
@@ -6568,7 +6576,7 @@
|
||||
"$ref": "#/components/schemas/VmMachineType"
|
||||
}
|
||||
],
|
||||
"description": "The machine_type (corresponding to a KVM version) used for this server.\nA null value indicates automatic selection of the best KVM machine type supported by the host node.\n\n| Value | Description |\n| ----- | ----------- |\n| pc_i440fx_1point5 | PC i440FX 1.5 |\n| pc_i440fx_2point11 | PC i440FX 2.11 |\n| pc_i440fx_4point1 | PC i440FX 4.1 |\n| pc_i440fx_4point2 | PC i440FX 4.2 |\n| pc_i440fx_5point0 | PC i440FX 5.0 |\n| pc_i440fx_5point1 | PC i440FX 5.1 |\n| pc_i440fx_7point2 | PC i440FX 7.2 |\n| pc_i440fx_8point2 | PC i440FX 8.2 |\n\n",
|
||||
"description": "The machine_type (corresponding to a KVM version) used for this server.\nA null value indicates automatic selection of the best KVM machine type supported by the host node.\n\n| Value | Description |\n| ----- | ----------- |\n| pc_i440fx_1point5 | PC i440FX 1.5 |\n| pc_i440fx_2point11 | PC i440FX 2.11 |\n| pc_i440fx_4point1 | PC i440FX 4.1 |\n| pc_i440fx_4point2 | PC i440FX 4.2 |\n| pc_i440fx_5point0 | PC i440FX 5.0 |\n| pc_i440fx_5point1 | PC i440FX 5.1 |\n| pc_i440fx_7point2 | PC i440FX 7.2 |\n| pc_i440fx_7point2point1 | PC i440FX 7.2.1 |\n| pc_i440fx_8point2 | PC i440FX 8.2 |\n\n",
|
||||
"nullable": true
|
||||
},
|
||||
"video_device": {
|
||||
@@ -6965,7 +6973,7 @@
|
||||
"$ref": "#/components/schemas/VmMachineType"
|
||||
}
|
||||
],
|
||||
"description": "Do not provide or set to null to keep existing machine type.\n\n| Value | Description |\n| ----- | ----------- |\n| pc_i440fx_1point5 | PC i440FX 1.5 |\n| pc_i440fx_2point11 | PC i440FX 2.11 |\n| pc_i440fx_4point1 | PC i440FX 4.1 |\n| pc_i440fx_4point2 | PC i440FX 4.2 |\n| pc_i440fx_5point0 | PC i440FX 5.0 |\n| pc_i440fx_5point1 | PC i440FX 5.1 |\n| pc_i440fx_7point2 | PC i440FX 7.2 |\n| pc_i440fx_8point2 | PC i440FX 8.2 |\n\n",
|
||||
"description": "Do not provide or set to null to keep existing machine type.\n\n| Value | Description |\n| ----- | ----------- |\n| pc_i440fx_1point5 | PC i440FX 1.5 |\n| pc_i440fx_2point11 | PC i440FX 2.11 |\n| pc_i440fx_4point1 | PC i440FX 4.1 |\n| pc_i440fx_4point2 | PC i440FX 4.2 |\n| pc_i440fx_5point0 | PC i440FX 5.0 |\n| pc_i440fx_5point1 | PC i440FX 5.1 |\n| pc_i440fx_7point2 | PC i440FX 7.2 |\n| pc_i440fx_7point2point1 | PC i440FX 7.2.1 |\n| pc_i440fx_8point2 | PC i440FX 8.2 |\n\n",
|
||||
"nullable": true
|
||||
},
|
||||
"automatic_machine_type": {
|
||||
@@ -7734,7 +7742,12 @@
|
||||
},
|
||||
"port_blocking": {
|
||||
"type": "boolean",
|
||||
"description": "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.",
|
||||
"description": "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 verified accounts.",
|
||||
"nullable": true
|
||||
},
|
||||
"separate_private_network_interface": {
|
||||
"type": "boolean",
|
||||
"description": "If true this will enable a separate private network interface for the server. This is only available for servers in a VPC.",
|
||||
"nullable": true
|
||||
},
|
||||
"password": {
|
||||
@@ -7993,21 +8006,33 @@
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"description": "The ID of this disk.",
|
||||
"format": "int64"
|
||||
"format": "int64",
|
||||
"x-oapi-codegen-extra-tags": {
|
||||
"tfsdk": "id"
|
||||
}
|
||||
},
|
||||
"size_gigabytes": {
|
||||
"type": "number",
|
||||
"description": "The size of the disk in GB.",
|
||||
"format": "double"
|
||||
"format": "double",
|
||||
"x-oapi-codegen-extra-tags": {
|
||||
"tfsdk": "size_gigabytes"
|
||||
}
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "A description of this disk.",
|
||||
"nullable": true
|
||||
"nullable": true,
|
||||
"x-oapi-codegen-extra-tags": {
|
||||
"tfsdk": "description"
|
||||
}
|
||||
},
|
||||
"primary": {
|
||||
"type": "boolean",
|
||||
"description": "A primary disk is treated differently from other disks."
|
||||
"description": "A primary disk is treated differently from other disks.",
|
||||
"x-oapi-codegen-extra-tags": {
|
||||
"tfsdk": "primary"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -8583,6 +8608,7 @@
|
||||
"nullable": true
|
||||
},
|
||||
"path": {
|
||||
"minLength": 1,
|
||||
"pattern": "/[A-Za-z0-9/.?=&+%_-]*",
|
||||
"type": "string",
|
||||
"description": "Leave null to accept the default '/' path.",
|
||||
@@ -9615,6 +9641,7 @@
|
||||
},
|
||||
"Networks": {
|
||||
"required": [
|
||||
"mac_address",
|
||||
"port_blocking",
|
||||
"recent_ddos",
|
||||
"v4",
|
||||
@@ -9661,6 +9688,10 @@
|
||||
},
|
||||
"description": "Any configured IPv6 reverse nameservers for this server. Please see our documentation for how this interacts with IPv6 nameserver settings at the account level.",
|
||||
"nullable": true
|
||||
},
|
||||
"mac_address": {
|
||||
"type": "string",
|
||||
"description": "The MAC address of this server's primary network interface. Customers may need this for ARP entries, DHCP reservations on a VPC, or MAC-based licensing."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -10387,12 +10418,12 @@
|
||||
},
|
||||
"network_incoming_kbps": {
|
||||
"type": "number",
|
||||
"description": "The incoming network data rate in Kb per second.",
|
||||
"description": "The incoming network data rate in KB per second (binary: 1 KB = 1024 bytes).",
|
||||
"format": "double"
|
||||
},
|
||||
"network_outgoing_kbps": {
|
||||
"type": "number",
|
||||
"description": "The outgoing network data rate in Kb per second.",
|
||||
"description": "The outgoing network data rate in KB per second (binary: 1 KB = 1024 bytes).",
|
||||
"format": "double"
|
||||
},
|
||||
"storage_usage_megabytes": {
|
||||
@@ -10402,12 +10433,12 @@
|
||||
},
|
||||
"storage_read_kbps": {
|
||||
"type": "number",
|
||||
"description": "The storage read rate in Kb per second.",
|
||||
"description": "The storage read rate in KB per second (binary: 1 KB = 1024 bytes).",
|
||||
"format": "double"
|
||||
},
|
||||
"storage_write_kbps": {
|
||||
"type": "number",
|
||||
"description": "The storage write rate in Kb per second.",
|
||||
"description": "The storage write rate in KB per second (binary: 1 KB = 1024 bytes).",
|
||||
"format": "double"
|
||||
},
|
||||
"storage_read_requests_per_second": {
|
||||
@@ -10783,6 +10814,11 @@
|
||||
}
|
||||
],
|
||||
"description": "The currently enabled advanced features, machine type and processor flags."
|
||||
},
|
||||
"is_under_maintenance": {
|
||||
"type": "boolean",
|
||||
"description": "If true, this server is currently under maintenance and most actions will not be available. If this is null the status was not checked.",
|
||||
"nullable": true
|
||||
}
|
||||
},
|
||||
"x-cli-entity-ref": "name"
|
||||
@@ -11871,7 +11907,10 @@
|
||||
"ThresholdAlert": {
|
||||
"required": [
|
||||
"alert_type",
|
||||
"description",
|
||||
"enabled",
|
||||
"name",
|
||||
"unit",
|
||||
"value"
|
||||
],
|
||||
"type": "object",
|
||||
@@ -11883,6 +11922,18 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "The display name of this threshold alert."
|
||||
},
|
||||
"unit": {
|
||||
"type": "string",
|
||||
"description": "The unit suffix for this alert's value (e.g. `\"%\"` or `\"requests/second\"`)."
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "A human-readable description of what this threshold alert measures."
|
||||
},
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"description": "If a threshold alert is not enabled it will not generate warnings for the user."
|
||||
@@ -11946,10 +11997,11 @@
|
||||
"network-outgoing",
|
||||
"data-transfer-used",
|
||||
"storage-used",
|
||||
"memory-used"
|
||||
"memory-used",
|
||||
"locked-backup-slots"
|
||||
],
|
||||
"type": "string",
|
||||
"description": "\n| Value | Description |\n| ----- | ----------- |\n| cpu | The alert is based off the average percentage of all CPU; 100% is the maximum possible even with multiple processors. A high average will prevent the server from responding quickly. |\n| storage-requests | The alert is based off The average number of requests (combined read and write) received by the storage subsystem. A high number of requests often indicates swap usage (due to memory exhaustion) and is associated with poor performance. |\n| network-incoming | The alert is based off the amount of data going into the server (from the internet and the LAN). A sudden increase may indicate the server is the victim of a DOS attack. |\n| network-outgoing | The alert is based off the amount of data coming out of the server (to the internet and the LAN). A sudden increase may indicate the server has been hacked and is being used for spam delivery. |\n| data-transfer-used | The alert is based off the percentage of your monthly data transfer limit. |\n| storage-used | The alert is based off the disk space consumed as a percentage of your total disk space. If the server runs out of disk space programs may fail to execute or be unable to create new files, or the server may become unresponsive. |\n| memory-used | The alert is based off the virtual memory consumed as a percentage of your physical memory. Virtual memory includes the swap file so the percentage may exceed 100% indicating that the server has run out of physical memory and is relying on swap space, which will generally cause poor performance. |\n\n",
|
||||
"description": "\n| Value | Description |\n| ----- | ----------- |\n| cpu | The alert is based off the average percentage of all CPU; 100% is the maximum possible even with multiple processors. A high average will prevent the server from responding quickly. |\n| storage-requests | The alert is based off The average number of requests (combined read and write) received by the storage subsystem. A high number of requests often indicates swap usage (due to memory exhaustion) and is associated with poor performance. |\n| network-incoming | The alert is based off the amount of data going into the server (from the internet and the LAN). A sudden increase may indicate the server is the victim of a DOS attack. |\n| network-outgoing | The alert is based off the amount of data coming out of the server (to the internet and the LAN). A sudden increase may indicate the server has been hacked and is being used for spam delivery. |\n| data-transfer-used | The alert is based off the percentage of your monthly data transfer limit. |\n| storage-used | The alert is based off the disk space consumed as a percentage of your total disk space. If the server runs out of disk space programs may fail to execute or be unable to create new files, or the server may become unresponsive. |\n| memory-used | The alert is based off the virtual memory consumed as a percentage of your physical memory. Virtual memory includes the swap file so the percentage may exceed 100% indicating that the server has run out of physical memory and is relying on swap space, which will generally cause poor performance. |\n| locked-backup-slots | The alert is based off the percentage of scheduled backup slots (daily, weekly, monthly) occupied by locked backups. When all slots are locked, automated backups cannot proceed. |\n\n",
|
||||
"x-enum-descriptions": [
|
||||
"The alert is based off the average percentage of all CPU; 100% is the maximum possible even with multiple processors. A high average will prevent the server from responding quickly.",
|
||||
"The alert is based off The average number of requests (combined read and write) received by the storage subsystem. A high number of requests often indicates swap usage (due to memory exhaustion) and is associated with poor performance.",
|
||||
@@ -11957,7 +12009,8 @@
|
||||
"The alert is based off the amount of data coming out of the server (to the internet and the LAN). A sudden increase may indicate the server has been hacked and is being used for spam delivery.",
|
||||
"The alert is based off the percentage of your monthly data transfer limit.",
|
||||
"The alert is based off the disk space consumed as a percentage of your total disk space. If the server runs out of disk space programs may fail to execute or be unable to create new files, or the server may become unresponsive.",
|
||||
"The alert is based off the virtual memory consumed as a percentage of your physical memory. Virtual memory includes the swap file so the percentage may exceed 100% indicating that the server has run out of physical memory and is relying on swap space, which will generally cause poor performance."
|
||||
"The alert is based off the virtual memory consumed as a percentage of your physical memory. Virtual memory includes the swap file so the percentage may exceed 100% indicating that the server has run out of physical memory and is relying on swap space, which will generally cause poor performance.",
|
||||
"The alert is based off the percentage of scheduled backup slots (daily, weekly, monthly) occupied by locked backups. When all slots are locked, automated backups cannot proceed."
|
||||
]
|
||||
},
|
||||
"ThresholdAlertsResponse": {
|
||||
@@ -12300,10 +12353,11 @@
|
||||
"pc_i440fx_5point0",
|
||||
"pc_i440fx_5point1",
|
||||
"pc_i440fx_7point2",
|
||||
"pc_i440fx_7point2point1",
|
||||
"pc_i440fx_8point2"
|
||||
],
|
||||
"type": "string",
|
||||
"description": "\n| Value | Description |\n| ----- | ----------- |\n| pc_i440fx_1point5 | PC i440FX 1.5 |\n| pc_i440fx_2point11 | PC i440FX 2.11 |\n| pc_i440fx_4point1 | PC i440FX 4.1 |\n| pc_i440fx_4point2 | PC i440FX 4.2 |\n| pc_i440fx_5point0 | PC i440FX 5.0 |\n| pc_i440fx_5point1 | PC i440FX 5.1 |\n| pc_i440fx_7point2 | PC i440FX 7.2 |\n| pc_i440fx_8point2 | PC i440FX 8.2 |\n\n",
|
||||
"description": "\n| Value | Description |\n| ----- | ----------- |\n| pc_i440fx_1point5 | PC i440FX 1.5 |\n| pc_i440fx_2point11 | PC i440FX 2.11 |\n| pc_i440fx_4point1 | PC i440FX 4.1 |\n| pc_i440fx_4point2 | PC i440FX 4.2 |\n| pc_i440fx_5point0 | PC i440FX 5.0 |\n| pc_i440fx_5point1 | PC i440FX 5.1 |\n| pc_i440fx_7point2 | PC i440FX 7.2 |\n| pc_i440fx_7point2point1 | PC i440FX 7.2.1 |\n| pc_i440fx_8point2 | PC i440FX 8.2 |\n\n",
|
||||
"x-enum-descriptions": [
|
||||
"PC i440FX 1.5",
|
||||
"PC i440FX 2.11",
|
||||
@@ -12312,6 +12366,7 @@
|
||||
"PC i440FX 5.0",
|
||||
"PC i440FX 5.1",
|
||||
"PC i440FX 7.2",
|
||||
"PC i440FX 7.2.1",
|
||||
"PC i440FX 8.2"
|
||||
]
|
||||
},
|
||||
|
||||
+100
-1
@@ -743,6 +743,16 @@
|
||||
"computed_optional_required": "computed_optional",
|
||||
"description": "Leave null to accept the default '/' path.",
|
||||
"validators": [
|
||||
{
|
||||
"custom": {
|
||||
"imports": [
|
||||
{
|
||||
"path": "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
|
||||
}
|
||||
],
|
||||
"schema_definition": "stringvalidator.LengthAtLeast(1)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"custom": {
|
||||
"imports": [
|
||||
@@ -852,7 +862,7 @@
|
||||
"name": "port_blocking",
|
||||
"bool": {
|
||||
"computed_optional_required": "computed_optional",
|
||||
"description": "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."
|
||||
"description": "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 verified accounts."
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -874,6 +884,13 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "separate_private_network_interface",
|
||||
"bool": {
|
||||
"computed_optional_required": "computed_optional",
|
||||
"description": "If true this will enable a separate private network interface for the server. This is only available for servers in a VPC."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "size",
|
||||
"string": {
|
||||
@@ -1020,6 +1037,88 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "disks",
|
||||
"list_nested": {
|
||||
"computed_optional_required": "computed_optional",
|
||||
"description": "The disks attached to this server. Leave null to let Binary Lane manage the server's disks. If specified, every disk must be listed, including the primary: exactly one entry must have `primary = true`, and its `id` and `description` are assigned by Binary Lane.",
|
||||
"nested_object": {
|
||||
"attributes": [
|
||||
{
|
||||
"name": "id",
|
||||
"int64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The ID of this disk."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "description",
|
||||
"string": {
|
||||
"computed_optional_required": "computed_optional",
|
||||
"description": "A label for this disk. Assigned by Binary Lane for the primary disk, so must be left null when `primary = true`. Changing this will destroy the disk and create a new one, losing any data on it. Disks that share a description are matched in the order they are listed.",
|
||||
"validators": [
|
||||
{
|
||||
"custom": {
|
||||
"imports": [
|
||||
{
|
||||
"path": "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
|
||||
}
|
||||
],
|
||||
"schema_definition": "stringvalidator.LengthAtLeast(1)"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "primary",
|
||||
"bool": {
|
||||
"computed_optional_required": "computed_optional",
|
||||
"description": "If `true` this is the primary disk, which the operating system is installed on. Exactly one disk must be the primary."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "size_gigabytes",
|
||||
"int64": {
|
||||
"computed_optional_required": "required",
|
||||
"description": "The size of the disk in GB. The sum across all disks cannot exceed `disk`, and any remainder is left unallocated.",
|
||||
"validators": [
|
||||
{
|
||||
"custom": {
|
||||
"imports": [
|
||||
{
|
||||
"path": "github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
|
||||
}
|
||||
],
|
||||
"schema_definition": "int64validator.AtLeast(1)"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"validators": [
|
||||
{
|
||||
"custom": {
|
||||
"schema_definition": "disksValidator{}"
|
||||
}
|
||||
}
|
||||
],
|
||||
"plan_modifiers": [
|
||||
{
|
||||
"custom": {
|
||||
"imports": [
|
||||
{
|
||||
"path": "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
|
||||
}
|
||||
],
|
||||
"schema_definition": "disksPlanModifier{}"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
{
|
||||
"name": "disks",
|
||||
"list_nested": {
|
||||
"computed_optional_required": "computed_optional",
|
||||
"description": "The disks attached to this server. Leave null to let Binary Lane manage the server's disks. If specified, every disk must be listed, including the primary: exactly one entry must have `primary = true`, and its `id` and `description` are assigned by Binary Lane.",
|
||||
"nested_object": {
|
||||
"attributes": [
|
||||
{
|
||||
"name": "id",
|
||||
"int64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The ID of this disk."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "description",
|
||||
"string": {
|
||||
"computed_optional_required": "computed_optional",
|
||||
"description": "A label for this disk. Assigned by Binary Lane for the primary disk, so must be left null when `primary = true`. Changing this will destroy the disk and create a new one, losing any data on it. Disks that share a description are matched in the order they are listed.",
|
||||
"validators": [
|
||||
{
|
||||
"custom": {
|
||||
"imports": [
|
||||
{
|
||||
"path": "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
|
||||
}
|
||||
],
|
||||
"schema_definition": "stringvalidator.LengthAtLeast(1)"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "primary",
|
||||
"bool": {
|
||||
"computed_optional_required": "computed_optional",
|
||||
"description": "If `true` this is the primary disk, which the operating system is installed on. Exactly one disk must be the primary."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "size_gigabytes",
|
||||
"int64": {
|
||||
"computed_optional_required": "required",
|
||||
"description": "The size of the disk in GB. The sum across all disks cannot exceed `disk`, and any remainder is left unallocated.",
|
||||
"validators": [
|
||||
{
|
||||
"custom": {
|
||||
"imports": [
|
||||
{
|
||||
"path": "github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
|
||||
}
|
||||
],
|
||||
"schema_definition": "int64validator.AtLeast(1)"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"validators": [
|
||||
{
|
||||
"custom": {
|
||||
"schema_definition": "disksValidator{}"
|
||||
}
|
||||
}
|
||||
],
|
||||
"plan_modifiers": [
|
||||
{
|
||||
"custom": {
|
||||
"imports": [
|
||||
{
|
||||
"path": "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
|
||||
}
|
||||
],
|
||||
"schema_definition": "disksPlanModifier{}"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,9 @@ cat <<<$(jq --tab '. + {"$schema": "https://raw.githubusercontent.com/hashicorp/
|
||||
ADVANCED_FEATURES_CONFIG=$(dirname "$0")/data/server_advanced_features.json
|
||||
cat <<<$(jq --tab --slurpfile adv_feat_cfg $ADVANCED_FEATURES_CONFIG '.resources[1].schema.attributes |= . + $adv_feat_cfg' $GENERATOR_CONFIG) >$GENERATOR_CONFIG
|
||||
|
||||
DISKS_CONFIG=$(dirname "$0")/data/server_disks.json
|
||||
cat <<<$(jq --tab --slurpfile disks_cfg $DISKS_CONFIG '.resources[1].schema.attributes |= . + $disks_cfg' $GENERATOR_CONFIG) >$GENERATOR_CONFIG
|
||||
|
||||
# Use set instead of list for server_ids in load_balancer resource
|
||||
jq --tab '
|
||||
.resources |= map(
|
||||
|
||||
@@ -37,6 +37,12 @@ cat <<<$(jq 'del(.paths."/images/{image_id}")' $OPENAPI_FILE) >$OPENAPI_FILE
|
||||
|
||||
# Add x-oapi-codegen-extra-tags so structs can be reflected
|
||||
|
||||
## Disk
|
||||
cat <<<$(jq '.components.schemas.Disk.properties.id += {"x-oapi-codegen-extra-tags": {"tfsdk": "id"}}' $OPENAPI_FILE) >$OPENAPI_FILE
|
||||
cat <<<$(jq '.components.schemas.Disk.properties.description += {"x-oapi-codegen-extra-tags": {"tfsdk": "description"}}' $OPENAPI_FILE) >$OPENAPI_FILE
|
||||
cat <<<$(jq '.components.schemas.Disk.properties.primary += {"x-oapi-codegen-extra-tags": {"tfsdk": "primary"}}' $OPENAPI_FILE) >$OPENAPI_FILE
|
||||
cat <<<$(jq '.components.schemas.Disk.properties.size_gigabytes += {"x-oapi-codegen-extra-tags": {"tfsdk": "size_gigabytes"}}' $OPENAPI_FILE) >$OPENAPI_FILE
|
||||
|
||||
## RouteEntryRequest
|
||||
cat <<<$(jq '.components.schemas.RouteEntryRequest.properties.destination += {"x-oapi-codegen-extra-tags": {"tfsdk": "destination"}}' $OPENAPI_FILE) >$OPENAPI_FILE
|
||||
cat <<<$(jq '.components.schemas.RouteEntryRequest.properties.description += {"x-oapi-codegen-extra-tags": {"tfsdk": "description"}}' $OPENAPI_FILE) >$OPENAPI_FILE
|
||||
|
||||
Reference in New Issue
Block a user