Compare commits

..

5 Commits

Author SHA1 Message Date
Oscar Hermoso 24f05a6266 📡 "advanced feature" flags (#75)
* 📡 wip - advanced features

* 📡 wip 2 - advanced features

* 📡 wip 3 - advanced features

* 📡 wip 4 - advanced features

* 📡 fix advanced feature check, clean up example

* 👨‍✈️ copilot: remove duplicate "password

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-04-25 09:10:20 +08:00
dependabot[bot] 86b980c91b 🐹 Bump golang.org/x/net from 0.34.0 to 0.36.0 (#70)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.34.0 to 0.36.0.
- [Commits](https://github.com/golang/net/compare/v0.34.0...v0.36.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-16 09:13:11 +08:00
dependabot[bot] 21b43d92b9 🐹 Bump the minor-patch group across 1 directory with 3 updates (#66)
Bumps the minor-patch group with 3 updates in the / directory: [github.com/hashicorp/terraform-plugin-docs](https://github.com/hashicorp/terraform-plugin-docs), [github.com/hashicorp/terraform-plugin-framework](https://github.com/hashicorp/terraform-plugin-framework) and [github.com/hashicorp/terraform-plugin-framework-validators](https://github.com/hashicorp/terraform-plugin-framework-validators).


Updates `github.com/hashicorp/terraform-plugin-docs` from 0.20.1 to 0.21.0
- [Release notes](https://github.com/hashicorp/terraform-plugin-docs/releases)
- [Changelog](https://github.com/hashicorp/terraform-plugin-docs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/hashicorp/terraform-plugin-docs/compare/v0.20.1...v0.21.0)

Updates `github.com/hashicorp/terraform-plugin-framework` from 1.13.0 to 1.14.1
- [Release notes](https://github.com/hashicorp/terraform-plugin-framework/releases)
- [Changelog](https://github.com/hashicorp/terraform-plugin-framework/blob/main/CHANGELOG.md)
- [Commits](https://github.com/hashicorp/terraform-plugin-framework/compare/v1.13.0...v1.14.1)

Updates `github.com/hashicorp/terraform-plugin-framework-validators` from 0.16.0 to 0.17.0
- [Release notes](https://github.com/hashicorp/terraform-plugin-framework-validators/releases)
- [Changelog](https://github.com/hashicorp/terraform-plugin-framework-validators/blob/main/CHANGELOG.md)
- [Commits](https://github.com/hashicorp/terraform-plugin-framework-validators/compare/v0.16.0...v0.17.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-16 09:10:51 +08:00
dependabot[bot] e70e10c4c9 🐈 Bump goreleaser/goreleaser-action in the minor-patch group (#64)
Bumps the minor-patch group with 1 update: [goreleaser/goreleaser-action](https://github.com/goreleaser/goreleaser-action).


Updates `goreleaser/goreleaser-action` from 6.1.0 to 6.2.1
- [Release notes](https://github.com/goreleaser/goreleaser-action/releases)
- [Commits](https://github.com/goreleaser/goreleaser-action/compare/9ed2f89a662bf1735a48bc8557fd212fa902bebf...90a3faa9d0182683851fbfa97ca1a2cb983bfca3)

---
updated-dependencies:
- dependency-name: goreleaser/goreleaser-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-16 09:10:30 +08:00
Oscar Hermoso 75a387e19d 🚮 fix: handle when resources are removed externally (#71) 2025-03-15 10:11:52 +08:00
23 changed files with 1653 additions and 361 deletions
+1 -1
View File
@@ -38,7 +38,7 @@ jobs:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.PASSPHRASE }}
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@9ed2f89a662bf1735a48bc8557fd212fa902bebf # v6.1.0
uses: goreleaser/goreleaser-action@90a3faa9d0182683851fbfa97ca1a2cb983bfca3 # v6.2.1
with:
args: release --clean
env:
+1
View File
@@ -19,6 +19,7 @@ Planned features:
- [x] Firewall Rules
- [x] Cloud Init
- [x] Updating server properties
- [x] "Advanced Features"
- [ ] Customised Backups
- [ ] Software
- [ ] IPV6
+33 -8
View File
@@ -27,17 +27,42 @@ data "binarylane_server" "example" {
### Read-Only
- `backups` (Boolean) If `true`, the server will be backed up twice per day. By default, backups are disabled.
- `disk` (Number) The amount of storage in GB assigned to the server.
- `image` (String) The slug of the selected operating system.
- `memory` (Number) The amount of memory in MB assigned to the server.
- `name` (String) The hostname of your server, such as vps01.yourcompany.com.
- `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:
- must be a multiple of 5
- \> 60 GB must be a multiple of 10
- \> 200 GB must be a multiple of 100
- `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.
- `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
- \> 2048 MB must be a multiple of 1024
- \> 16384 MB must be a multiple of 2048
- \> 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.
- `private_ipv4_addresses` (List of String) The private IPv4 addresses assigned to the server.
- `public_ipv4_addresses` (List of String) The public IPv4 addresses assigned to the server.
- `region` (String) The slug of the selected region.
- `size` (String) The slug of the selected size.
- `ssh_keys` (List of Number) This is a list of SSH key ids that were added to the server during creation.
- `user_data` (String) A script or cloud-config YAML file to configure the server.
- `vpc_id` (Number) ID of the Virtual Private Cloud (VPC) the server is connected to.
- `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.
- `user_data` (String) A script or cloud-config YAML file to configure the server. Can only be specified if the OS image supports UserData (i.e. not Windows). See more: https://cloudinit.readthedocs.io/en/latest/explanation/format.html#user-data-script
- `vpc_id` (Number) Leave null to use default (public) network for the selected region.
<a id="nestedatt--advanced_features"></a>
### Nested Schema for `advanced_features`
Read-Only:
- `cloud_init` (Boolean)
- `driver_disk` (Boolean)
- `emulated_devices` (Boolean)
- `emulated_hyperv` (Boolean)
- `emulated_tpm` (Boolean)
- `local_rtc` (Boolean)
- `nested_virt` (Boolean)
- `qemu_guest_agent` (Boolean)
- `uefi_boot` (Boolean)
- `unset_uuid` (Boolean)
+21
View File
@@ -38,6 +38,7 @@ resource "binarylane_server" "example" {
### Optional
- `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:
- must be a multiple of 5
@@ -65,6 +66,26 @@ resource "binarylane_server" "example" {
- `private_ipv4_addresses` (List of String) The private IPv4 addresses assigned to the server.
- `public_ipv4_addresses` (List of String) The public IPv4 addresses assigned to the server.
<a id="nestedatt--advanced_features"></a>
### Nested Schema for `advanced_features`
Optional:
- `driver_disk` (Boolean) When this option is enabled a copy of the KVM driver disc for Windows ("virtio-win.iso") will be attached to your server as a virtual CD. This option can also be used in combination with your own attached backup when installing Windows.
- `emulated_devices` (Boolean) When emulated devices is enabled, the KVM specific "VirtIO" disk drive and network devices are removed, and replaced with emulated versions of physical hardware: an old IDE HDD and an Intel E1000 network card. Emulated devices are much slower than the VirtIO devices, and so this option should not be enabled unless absolutely necessary.
- `emulated_hyperv` (Boolean) Enable HyperV (a hypervisor produced by Microsoft) support. Enabled by default on Windows servers, generally of no value for non-Windows servers.
- `emulated_tpm` (Boolean) When enabled this provides an emulated TPM v1.2 device to your Cloud Server. Warning: the TPM state is not backed up.
- `local_rtc` (Boolean) When a server is booted the virtual BIOS receives the current date and time from the host node. The BIOS does not have an explicit timezone, so the timezone used is implicit and must be understood by the operating system. Most operating systems other than Windows expect the time to be UTC since it allows the operating system to control the timezone used when displaying the time. Our Windows installations have also been customized to use UTC, but when using your own installation of Windows this should be set to the host node's local timezone.
- `nested_virt` (Boolean) When this option is enabled the functionality necessary to run your own KVM servers within your server is enabled. Note that all the networking limits - one MAC address per VPS, restricted to specific IPs - still apply to public cloud so this feature is generally only useful in combination with Virtual Private Cloud.
- `unset_uuid` (Boolean) When this option is NOT enabled a 128-bit unique identifier is exposed to your server through the virtual BIOS. Each server receives a different UUID. Some proprietary licensed software utilize this identifier to "tie" the license to a specific server.
Read-Only:
- `cloud_init` (Boolean) When this option is enabled the Cloud Server will be provided a datasource for the cloud-init service.
- `qemu_guest_agent` (Boolean) When this option is enabled the server will allow QEMU Guest Agent to perform password reset without rebooting.
- `uefi_boot` (Boolean) When this option is enabled the Cloud Server will use UEFI instead of legacy PC BIOS.
<a id="nestedatt--timeouts"></a>
### Nested Schema for `timeouts`
+5 -4
View File
@@ -1,9 +1,10 @@
package main
//go:generate ./internal/binarylane/fetch-openapi.sh
//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=internal/binarylane/client.cfg.yml internal/binarylane/openapi.json
//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=internal/binarylane/types.cfg.yml internal/binarylane/openapi.json
//go:generate go run github.com/hashicorp/terraform-plugin-codegen-openapi/cmd/tfplugingen-openapi generate --config=./provider_gen_config.yml internal/binarylane/openapi.json --output=./provider_code_spec.json
//go:generate ./scripts/fetch-openapi.sh
//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=internal/binarylane/client.cfg.yml ./openapi.json
//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=internal/binarylane/types.cfg.yml ./openapi.json
//go:generate go run github.com/hashicorp/terraform-plugin-codegen-openapi/cmd/tfplugingen-openapi generate --config=./provider_gen_config.yml ./openapi.json --output=./provider_code_spec.json
//go:generate ./scripts/extend-provider.sh
//go:generate mkdir -p internal/resources internal/data_sources
//go:generate go run github.com/hashicorp/terraform-plugin-codegen-framework/cmd/tfplugingen-framework generate resources --input=./provider_code_spec.json --output=./internal/resources --package=resources
//go:generate go run github.com/hashicorp/terraform-plugin-codegen-framework/cmd/tfplugingen-framework generate data-sources --input=./provider_code_spec.json --output=./internal/data_sources --package=data_sources
+20 -18
View File
@@ -1,15 +1,17 @@
module terraform-provider-binarylane
go 1.22.7
go 1.23.0
toolchain go1.24.1
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.20.1
github.com/hashicorp/terraform-plugin-framework v1.13.0
github.com/hashicorp/terraform-plugin-docs v0.21.0
github.com/hashicorp/terraform-plugin-framework v1.14.1
github.com/hashicorp/terraform-plugin-framework-timeouts v0.5.0
github.com/hashicorp/terraform-plugin-framework-validators v0.16.0
github.com/hashicorp/terraform-plugin-framework-validators v0.17.0
github.com/hashicorp/terraform-plugin-go v0.26.0
github.com/hashicorp/terraform-plugin-log v0.9.0
github.com/hashicorp/terraform-plugin-testing v1.11.0
@@ -23,14 +25,14 @@ 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.0-alpha.2 // indirect
github.com/ProtonMail/go-crypto v1.1.3 // indirect
github.com/agext/levenshtein v1.2.2 // 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
github.com/bahlo/generic-list-go v0.2.0 // indirect
github.com/bgentry/speakeasy v0.1.0 // indirect
github.com/bmatcuk/doublestar/v4 v4.7.1 // indirect
github.com/bmatcuk/doublestar/v4 v4.8.1 // indirect
github.com/buger/jsonparser v1.1.1 // indirect
github.com/cloudflare/circl v1.3.7 // indirect
github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect
@@ -43,7 +45,7 @@ require (
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/hashicorp/cli v1.1.6 // indirect
github.com/hashicorp/cli v1.1.7 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-checkpoint v0.5.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
@@ -54,11 +56,11 @@ require (
github.com/hashicorp/go-retryablehttp v0.7.7 // 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.0 // indirect
github.com/hashicorp/hc-install v0.9.1 // indirect
github.com/hashicorp/hcl/v2 v2.23.0 // indirect
github.com/hashicorp/logutils v1.0.0 // indirect
github.com/hashicorp/terraform-exec v0.21.0 // indirect
github.com/hashicorp/terraform-json v0.23.0 // indirect
github.com/hashicorp/terraform-exec v0.22.0 // indirect
github.com/hashicorp/terraform-json v0.24.0 // indirect
github.com/hashicorp/terraform-plugin-codegen-spec v0.2.0 // indirect
github.com/hashicorp/terraform-plugin-sdk/v2 v2.35.0 // indirect
github.com/hashicorp/terraform-registry-address v0.2.4 // indirect
@@ -69,7 +71,7 @@ require (
github.com/invopop/yaml v0.3.1 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
@@ -97,15 +99,15 @@ 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.15.0 // indirect
github.com/zclconf/go-cty v1.16.2 // indirect
go.abhg.dev/goldmark/frontmatter v0.2.0 // indirect
golang.org/x/crypto v0.32.0 // indirect
golang.org/x/crypto v0.35.0 // indirect
golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 // indirect
golang.org/x/mod v0.21.0 // indirect
golang.org/x/net v0.34.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/mod v0.22.0 // indirect
golang.org/x/net v0.36.0 // indirect
golang.org/x/sync v0.11.0 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/text v0.22.0 // indirect
golang.org/x/tools v0.22.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 // indirect
+42 -44
View File
@@ -13,8 +13,8 @@ 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.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/ProtonMail/go-crypto v1.1.0-alpha.2 h1:bkyFVUP+ROOARdgCiJzNQo2V2kiB97LyUpzH9P6Hrlg=
github.com/ProtonMail/go-crypto v1.1.0-alpha.2/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
github.com/ProtonMail/go-crypto v1.1.3 h1:nRBOetoydLeUb4nHajyO2bKqMLfWQ/ZPwkXqXxPxCFk=
github.com/ProtonMail/go-crypto v1.1.3/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
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=
@@ -30,8 +30,8 @@ github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xW
github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
github.com/bmatcuk/doublestar/v4 v4.7.1 h1:fdDeAqgT47acgwd9bd9HxJRDmc9UAmPpc+2m0CXv75Q=
github.com/bmatcuk/doublestar/v4 v4.7.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/bmatcuk/doublestar/v4 v4.8.1 h1:54Bopc5c2cAvhLRAzqOGCYHYyhcDHsFF4wWIR5wKP38=
github.com/bmatcuk/doublestar/v4 v4.8.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA=
github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8=
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
@@ -42,8 +42,8 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
github.com/cyphar/filepath-securejoin v0.2.5 h1:6iR5tXJ/e6tJZzzdMc1km3Sa7RRIVBKAK32O2s7AYfo=
github.com/cyphar/filepath-securejoin v0.2.5/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -67,10 +67,10 @@ github.com/getkin/kin-openapi v0.127.0 h1:Mghqi3Dhryf3F8vR370nN67pAERW+3a95vomb3
github.com/getkin/kin-openapi v0.127.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM=
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.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU=
github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys=
github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY=
github.com/go-git/go-billy/v5 v5.6.0 h1:w2hPNtoehvJIxR00Vb4xX94qHQi/ApZfX+nBE2Cjio8=
github.com/go-git/go-billy/v5 v5.6.0/go.mod h1:sFDq7xD3fn3E0GOwUSZqHo9lrkmx8xJhA0ZrfvjBRGM=
github.com/go-git/go-git/v5 v5.13.0 h1:vLn5wlGIh/X78El6r3Jr+30W16Blk0CTcxTYcYPWi5E=
github.com/go-git/go-git/v5 v5.13.0/go.mod h1:Wjo7/JyVKtQgUNdXYXIepzWfJQkUEIGvkvVkiXRR/zw=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
@@ -107,8 +107,8 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLe
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/cli v1.1.6 h1:CMOV+/LJfL1tXCOKrgAX0uRKnzjj/mpmqNXloRSy2K8=
github.com/hashicorp/cli v1.1.6/go.mod h1:MPon5QYlgjjo0BSoAiN0ESeT5fRzDjVRp+uioJ0piz4=
github.com/hashicorp/cli v1.1.7 h1:/fZJ+hNdwfTSfsxMBa9WWMlfjUZbX8/LnUxgAd7lCVU=
github.com/hashicorp/cli v1.1.7/go.mod h1:e6Mfpga9OCT1vqzFuoGZiiF/KaG9CbUfO5s3ghU3YgU=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@@ -133,30 +133,30 @@ github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/C
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.0 h1:2dIk8LcvANwtv3QZLckxcjyF5w8KVtiMxu6G6eLhghE=
github.com/hashicorp/hc-install v0.9.0/go.mod h1:+6vOP+mf3tuGgMApVYtmsnDoKWMDcFXeTxCACYZ8SFg=
github.com/hashicorp/hc-install v0.9.1 h1:gkqTfE3vVbafGQo6VZXcy2v5yoz2bE0+nhZXruCuODQ=
github.com/hashicorp/hc-install v0.9.1/go.mod h1:pWWvN/IrfeBK4XPeXXYkL6EjMufHkCK5DvwxeLKuBf0=
github.com/hashicorp/hcl/v2 v2.23.0 h1:Fphj1/gCylPxHutVSEOf2fBOh1VE4AuLV7+kbJf3qos=
github.com/hashicorp/hcl/v2 v2.23.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA=
github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/terraform-exec v0.21.0 h1:uNkLAe95ey5Uux6KJdua6+cv8asgILFVWkd/RG0D2XQ=
github.com/hashicorp/terraform-exec v0.21.0/go.mod h1:1PPeMYou+KDUSSeRE9szMZ/oHf4fYUmB923Wzbq1ICg=
github.com/hashicorp/terraform-json v0.23.0 h1:sniCkExU4iKtTADReHzACkk8fnpQXrdD2xoR+lppBkI=
github.com/hashicorp/terraform-json v0.23.0/go.mod h1:MHdXbBAbSg0GvzuWazEGKAn/cyNfIB7mN6y7KJN6y2c=
github.com/hashicorp/terraform-exec v0.22.0 h1:G5+4Sz6jYZfRYUCg6eQgDsqTzkNXV+fP8l+uRmZHj64=
github.com/hashicorp/terraform-exec v0.22.0/go.mod h1:bjVbsncaeh8jVdhttWYZuBGj21FcYw6Ia/XfHcNO7lQ=
github.com/hashicorp/terraform-json v0.24.0 h1:rUiyF+x1kYawXeRth6fKFm/MdfBS6+lW4NbeATsYz8Q=
github.com/hashicorp/terraform-json v0.24.0/go.mod h1:Nfj5ubo9xbu9uiAoZVBsNOjvNKB66Oyrvtit74kC7ow=
github.com/hashicorp/terraform-plugin-codegen-framework v0.4.1 h1:eaI/3dsu2T5QAXbA+7N+B+UBj20GdtYnsRuYypKh3S4=
github.com/hashicorp/terraform-plugin-codegen-framework v0.4.1/go.mod h1:kpYM23L7NtcfaQdWAN0QFkV/lU0w16qJ2ddAPCI4zAg=
github.com/hashicorp/terraform-plugin-codegen-openapi v0.3.0 h1:IKpc337XKk50QyQPSxLrHwdqSo1E2XqCMxFkWsZcTvc=
github.com/hashicorp/terraform-plugin-codegen-openapi v0.3.0/go.mod h1:tT6wl80h7nsMBw+1yZRgJXi+Ys85PUai11weDqysvp4=
github.com/hashicorp/terraform-plugin-codegen-spec v0.2.0 h1:91dQG1A/DxP6vRz9GiytDTrZTXDbhHPvmpYnAyWA/Vw=
github.com/hashicorp/terraform-plugin-codegen-spec v0.2.0/go.mod h1:fywrEKpordQypmAjz/HIfm2LuNVmyJ6KDe8XT9GdJxQ=
github.com/hashicorp/terraform-plugin-docs v0.20.1 h1:Fq7E/HrU8kuZu3hNliZGwloFWSYfWEOWnylFhYQIoys=
github.com/hashicorp/terraform-plugin-docs v0.20.1/go.mod h1:Yz6HoK7/EgzSrHPB9J/lWFzwl9/xep2OPnc5jaJDV90=
github.com/hashicorp/terraform-plugin-framework v1.13.0 h1:8OTG4+oZUfKgnfTdPTJwZ532Bh2BobF4H+yBiYJ/scw=
github.com/hashicorp/terraform-plugin-framework v1.13.0/go.mod h1:j64rwMGpgM3NYXTKuxrCnyubQb/4VKldEKlcG8cvmjU=
github.com/hashicorp/terraform-plugin-docs v0.21.0 h1:yoyA/Y719z9WdFJAhpUkI1jRbKP/nteVNBaI3hW7iQ8=
github.com/hashicorp/terraform-plugin-docs v0.21.0/go.mod h1:J4Wott1J2XBKZPp/NkQv7LMShJYOcrqhQ2myXBcu64s=
github.com/hashicorp/terraform-plugin-framework v1.14.1 h1:jaT1yvU/kEKEsxnbrn4ZHlgcxyIfjvZ41BLdlLk52fY=
github.com/hashicorp/terraform-plugin-framework v1.14.1/go.mod h1:xNUKmvTs6ldbwTuId5euAtg37dTxuyj3LHS3uj7BHQ4=
github.com/hashicorp/terraform-plugin-framework-timeouts v0.5.0 h1:I/N0g/eLZ1ZkLZXUQ0oRSXa8YG/EF0CEuQP1wXdrzKw=
github.com/hashicorp/terraform-plugin-framework-timeouts v0.5.0/go.mod h1:t339KhmxnaF4SzdpxmqW8HnQBHVGYazwtfxU0qCs4eE=
github.com/hashicorp/terraform-plugin-framework-validators v0.16.0 h1:O9QqGoYDzQT7lwTXUsZEtgabeWW96zUBh47Smn2lkFA=
github.com/hashicorp/terraform-plugin-framework-validators v0.16.0/go.mod h1:Bh89/hNmqsEWug4/XWKYBwtnw3tbz5BAy1L1OgvbIaY=
github.com/hashicorp/terraform-plugin-framework-validators v0.17.0 h1:0uYQcqqgW3BMyyve07WJgpKorXST3zkpzvrOnf3mpbg=
github.com/hashicorp/terraform-plugin-framework-validators v0.17.0/go.mod h1:VwdfgE/5Zxm43flraNa0VjcvKQOGVrcO4X8peIri0T0=
github.com/hashicorp/terraform-plugin-go v0.26.0 h1:cuIzCv4qwigug3OS7iKhpGAbZTiypAfFQmw8aE65O2M=
github.com/hashicorp/terraform-plugin-go v0.26.0/go.mod h1:+CXjuLDiFgqR+GcrM5a2E2Kal5t5q2jb0E3D57tTdNY=
github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0=
@@ -201,11 +201,10 @@ 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.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
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-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.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
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-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
@@ -268,8 +267,8 @@ github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A=
github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo=
github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY=
github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M=
github.com/speakeasy-api/openapi-overlay v0.9.0 h1:Wrz6NO02cNlLzx1fB093lBlYxSI54VRhy1aSutx0PQg=
github.com/speakeasy-api/openapi-overlay v0.9.0/go.mod h1:f5FloQrHA7MsxYg9djzMD5h6dxrHjVVByWKh7an8TRc=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
@@ -312,8 +311,8 @@ 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.15.0 h1:tTCRWxsexYUmtt/wVxgDClUe+uQusuI443uL6e+5sXQ=
github.com/zclconf/go-cty v1.15.0/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
github.com/zclconf/go-cty v1.16.2 h1:LAJSwc3v81IRBZyUVQDUdZ7hs3SYs9jv0eZJDWHD/70=
github.com/zclconf/go-cty v1.16.2/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
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=
@@ -333,14 +332,14 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
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.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
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=
@@ -351,14 +350,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.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
golang.org/x/net v0.36.0 h1:vWF2fRbw4qslQsQzgFqZff+BItCvGFQqKzKIzx1rmoA=
golang.org/x/net v0.36.0/go.mod h1:bFmbeoIPfrw4sMHNhb4J9f6+tPziuGjq7Jk/38fxi1I=
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.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -381,11 +380,10 @@ golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
@@ -396,8 +394,8 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
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=
+12 -39
View File
@@ -36,20 +36,6 @@ const (
AddDiskTypeAddDisk AddDiskType = "add_disk"
)
// Defines values for AdvancedFeature.
const (
CloudInit AdvancedFeature = "cloud-init"
DriverDisk AdvancedFeature = "driver-disk"
EmulatedDevices AdvancedFeature = "emulated-devices"
EmulatedHyperv AdvancedFeature = "emulated-hyperv"
EmulatedTpm AdvancedFeature = "emulated-tpm"
LocalRtc AdvancedFeature = "local-rtc"
NestedVirt AdvancedFeature = "nested-virt"
QemuGuestAgent AdvancedFeature = "qemu-guest-agent"
UefiBoot AdvancedFeature = "uefi-boot"
UnsetUuid AdvancedFeature = "unset-uuid"
)
// Defines values for AdvancedFirewallRuleAction.
const (
Accept AdvancedFirewallRuleAction = "accept"
@@ -421,6 +407,7 @@ const (
PcI440fx5point0 VmMachineType = "pc_i440fx_5point0"
PcI440fx5point1 VmMachineType = "pc_i440fx_5point1"
PcI440fx7point2 VmMachineType = "pc_i440fx_7point2"
PcI440fx8point2 VmMachineType = "pc_i440fx_8point2"
)
// Account defines model for Account.
@@ -568,21 +555,6 @@ type AddDisk struct {
// AddDiskType defines model for AddDisk.Type.
type AddDiskType string
// AdvancedFeature
// | Value | Description |
// | ----- | ----------- |
// | emulated-hyperv | Enable HyperV (a hypervisor produced by Microsoft) support. Enabled by default on Windows servers, generally of no value for non-Windows servers. |
// | emulated-devices | When emulated devices is enabled, the KVM specific "VirtIO" disk drive and network devices are removed, and replaced with emulated versions of physical hardware: an old IDE HDD and an Intel E1000 network card. Emulated devices are much slower than the VirtIO devices, and so this option should not be enabled unless absolutely necessary. |
// | nested-virt | When this option is enabled the functionality necessary to run your own KVM servers within your server is enabled. Note that all the networking limits - one MAC address per VPS, restricted to specific IPs - still apply to public cloud so this is feature is generally only useful in combination with Virtual Private Cloud. |
// | driver-disk | When this option is enabled a copy of the KVM driver disc for Windows ("virtio-win.iso") will be attached to your server as a virtual CD. This option can also be used in combination with your own attached backup when installing Windows. |
// | unset-uuid | When this option is NOT enabled a 128-bit unique identifier is exposed to your server through the virtual BIOS. Each server receives a different UUID. Some propriety licensed software utilise this identifier to "tie" the license to a specific server. |
// | local-rtc | When a server is booted the virtual BIOS receives the current date and time from the host node. The BIOS does not have an explicit timezone, so the timezone used is implicit and must be understood by the operating system. Most operating systems other than Windows expect the time to be UTC since it allows the operating system to control the timezone used when displaying the time. Our Windows installations have also been customized to use UTC, but when using your own installation of Windows this should be set to the host node's local timezone. |
// | emulated-tpm | When enabled this provides an emulated TPM v1.2 device to your Cloud Server. Warning: the TPM state is not backed up. |
// | cloud-init | (Read-Only) When this option is enabled the Cloud Server will be provided a datasource for the cloud-init service. |
// | qemu-guest-agent | (Read-Only) When this option is enabled the server will allow QEMU Guest Agent to perform password reset without rebooting. |
// | uefi-boot | (Read-Only) When this option is enabled the Cloud Server will use UEFI instead of legacy PC BIOS. |
type AdvancedFeature string
// AdvancedFirewallRule defines model for AdvancedFirewallRule.
type AdvancedFirewallRule struct {
// Action The action to take when there is a match on this rule.
@@ -629,7 +601,7 @@ type AdvancedFirewallRulesResponse struct {
// AdvancedServerFeatures defines model for AdvancedServerFeatures.
type AdvancedServerFeatures struct {
// EnabledAdvancedFeatures A list of the currently enabled advanced features for this server.
EnabledAdvancedFeatures *[]AdvancedFeature `json:"enabled_advanced_features,omitempty"`
EnabledAdvancedFeatures *[]string `json:"enabled_advanced_features,omitempty"`
// MachineType The machine_type (corresponding to a KVM version) used for this server.
// A null value indicates automatic selection of the best KVM machine type supported by the host node.
@@ -680,7 +652,7 @@ type AttachedBackup struct {
// AvailableAdvancedServerFeatures defines model for AvailableAdvancedServerFeatures.
type AvailableAdvancedServerFeatures struct {
// AdvancedFeatures A list of the advanced features available for this server.
AdvancedFeatures *[]AdvancedFeature `json:"advanced_features,omitempty"`
AdvancedFeatures *[]string `json:"advanced_features,omitempty"`
// MachineTypes A list of the machine types available for this server.
MachineTypes *[]VmMachineType `json:"machine_types,omitempty"`
@@ -809,7 +781,7 @@ type ChangeAdvancedFeatures struct {
AutomaticProcessorModel *bool `json:"automatic_processor_model"`
// EnabledAdvancedFeatures Do not provide or set to null to keep existing advanced features. Provide an empty array to disable all advanced features, otherwise provide an array with selected advanced features. If provided, any currently enabled advanced features that aren't included will be disabled.
EnabledAdvancedFeatures *[]AdvancedFeature `json:"enabled_advanced_features"`
EnabledAdvancedFeatures *[]string `json:"enabled_advanced_features"`
// MachineType Do not provide or set to null to keep existing machine type.
MachineType *VmMachineType `json:"machine_type"`
@@ -2990,13 +2962,14 @@ type VideoDevice string
// VmMachineType
// | Value | Description |
// | ----- | ----------- |
// | pc_i440fx_1point5 | PC I440 FX 1.5 |
// | pc_i440fx_2point11 | PC I440 FX 2.11 |
// | pc_i440fx_4point1 | PC I440 FX 4.1 |
// | pc_i440fx_4point2 | PC I440 FX 4.2 |
// | pc_i440fx_5point0 | PC I440 FX 5.0 |
// | pc_i440fx_5point1 | PC I440 FX 5.1 |
// | pc_i440fx_7point2 | PC I440 FX 7.2 |
// | pc_i440fx_1point5 | PC i440FX 1.5 |
// | pc_i440fx_2point11 | PC i440FX 2.11 |
// | pc_i440fx_4point1 | PC i440FX 4.1 |
// | pc_i440fx_4point2 | PC i440FX 4.2 |
// | pc_i440fx_5point0 | PC i440FX 5.0 |
// | pc_i440fx_5point1 | PC i440FX 5.1 |
// | pc_i440fx_7point2 | PC i440FX 7.2 |
// | pc_i440fx_8point2 | PC i440FX 8.2 |
type VmMachineType string
// Vpc defines model for Vpc.
@@ -239,6 +239,12 @@ func (r *loadBalancerResource) Read(ctx context.Context, req resource.ReadReques
return
}
if lbResp.StatusCode() == http.StatusNotFound {
tflog.Warn(ctx, fmt.Sprintf("Load balancer not found, removing from state: id=%s, name=%s", data.Id.String(), data.Name.ValueString()))
resp.State.RemoveResource(ctx)
return
}
if lbResp.StatusCode() != http.StatusOK {
resp.Diagnostics.AddError(
"Unexpected HTTP status code reading load balancer",
+33 -109
View File
@@ -4,10 +4,12 @@ import (
"context"
"fmt"
"net/http"
"slices"
"terraform-provider-binarylane/internal/resources"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/types"
)
@@ -27,11 +29,12 @@ type serverDataSource struct {
type serverDataModel struct {
resources.ServerModel
PublicIpv4Addresses types.List `tfsdk:"public_ipv4_addresses"`
PrivateIPv4Addresses types.List `tfsdk:"private_ipv4_addresses"`
Permalink types.String `tfsdk:"permalink"`
Memory types.Int32 `tfsdk:"memory"`
Disk types.Int32 `tfsdk:"disk"`
PublicIpv4Addresses types.List `tfsdk:"public_ipv4_addresses"`
PrivateIPv4Addresses types.List `tfsdk:"private_ipv4_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) {
@@ -58,10 +61,10 @@ func (d *serverDataSource) Metadata(ctx context.Context, req datasource.Metadata
func (d *serverDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
ds, err := convertResourceSchemaToDataSourceSchema(
resources.ServerResourceSchema(ctx),
serverSchema(ctx),
AttributeConfig{
RequiredAttributes: &[]string{"id"},
ExcludedAttributes: &[]string{"password"},
ExcludedAttributes: &[]string{"password", "public_ipv4_count", "password_change_supported", "timeouts"},
})
if err != nil {
resp.Diagnostics.AddError("Failed to convert resource schema to data source schema", err.Error())
@@ -69,110 +72,10 @@ func (d *serverDataSource) Schema(ctx context.Context, req datasource.SchemaRequ
}
resp.Schema = *ds
resp.Schema.Description = "Retrieve details about a BinaryLane Server."
// Overrides
id := resp.Schema.Attributes["id"]
resp.Schema.Attributes["id"] = schema.Int64Attribute{
Description: id.GetDescription(),
MarkdownDescription: id.GetMarkdownDescription(),
Required: true, // ID is required to find the server
}
nameDescription := "The hostname of your server, such as vps01.yourcompany.com."
resp.Schema.Attributes["name"] = &schema.StringAttribute{
Description: nameDescription,
MarkdownDescription: nameDescription,
Optional: false,
Required: false,
Computed: true,
}
backupsDescription := "If `true`, the server will be backed up twice per day. By default, backups are disabled."
resp.Schema.Attributes["backups"] = &schema.BoolAttribute{
Description: backupsDescription,
MarkdownDescription: backupsDescription,
Optional: false,
Required: false,
Computed: true,
}
sshKeysDescription := "This is a list of SSH key ids that were added to the server during creation."
resp.Schema.Attributes["ssh_keys"] = &schema.ListAttribute{
ElementType: types.Int64Type,
Description: sshKeysDescription,
MarkdownDescription: sshKeysDescription,
Optional: false,
Required: false,
Computed: true,
}
userDataDescription := "A script or cloud-config YAML file to configure the server."
resp.Schema.Attributes["user_data"] = &schema.StringAttribute{
Description: userDataDescription,
MarkdownDescription: userDataDescription,
Optional: false,
Required: false,
Computed: true,
}
vpcIdDescription := "ID of the Virtual Private Cloud (VPC) the server is connected to."
resp.Schema.Attributes["vpc_id"] = &schema.Int64Attribute{
Description: vpcIdDescription,
MarkdownDescription: vpcIdDescription,
Optional: false,
Required: false,
Computed: true,
}
// Additional attributes
resp.Schema.Attributes["permalink"] = &schema.StringAttribute{
Description: "A randomly generated two-word identifier assigned to servers in regions that support this feature",
MarkdownDescription: "A randomly generated two-word identifier assigned to servers in regions that support this feature",
Optional: false,
Required: false,
Computed: true,
}
publicIpv4AddressesDescription := "The public IPv4 addresses assigned to the server."
resp.Schema.Attributes["public_ipv4_addresses"] = &schema.ListAttribute{
Description: publicIpv4AddressesDescription,
MarkdownDescription: publicIpv4AddressesDescription,
ElementType: types.StringType,
Optional: false,
Required: false,
Computed: true,
}
privateIpv4AddressesDescription := "The private IPv4 addresses assigned to the server."
resp.Schema.Attributes["private_ipv4_addresses"] = &schema.ListAttribute{
Description: privateIpv4AddressesDescription,
MarkdownDescription: privateIpv4AddressesDescription,
ElementType: types.StringType,
Optional: false,
Required: false,
Computed: true,
}
memoryDescription := "The amount of memory in MB assigned to the server."
resp.Schema.Attributes["memory"] = &schema.Int32Attribute{
Description: memoryDescription,
MarkdownDescription: memoryDescription,
Optional: false,
Required: false,
Computed: true,
}
diskDescription := "The amount of storage in GB assigned to the server."
resp.Schema.Attributes["disk"] = &schema.Int32Attribute{
Description: diskDescription,
MarkdownDescription: diskDescription,
Optional: false,
Required: false,
Computed: true,
}
}
func (d *serverDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var diag diag.Diagnostics
var data serverDataModel
// Read Terraform configuration data into the model
@@ -211,6 +114,27 @@ 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.SourceAndDestinationCheck = types.BoolPointerValue(serverResp.JSON200.Server.Networks.SourceAndDestinationCheck)
advFeat := *serverResp.JSON200.Server.AdvancedFeatures.EnabledAdvancedFeatures
data.AdvancedFeatures, diags = resources.NewAdvancedFeaturesValue(
resources.AdvancedFeaturesValue{}.AttributeTypes(ctx),
map[string]attr.Value{
"emulated_hyperv": types.BoolValue(slices.Contains(advFeat, "emulated-hyperv")),
"emulated_devices": types.BoolValue(slices.Contains(advFeat, "emulated-devices")),
"nested_virt": types.BoolValue(slices.Contains(advFeat, "nested-virt")),
"driver_disk": types.BoolValue(slices.Contains(advFeat, "driver-disk")),
"unset_uuid": types.BoolValue(slices.Contains(advFeat, "unset-uuid")),
"local_rtc": types.BoolValue(slices.Contains(advFeat, "local-rtc")),
"emulated_tpm": types.BoolValue(slices.Contains(advFeat, "emulated-tpm")),
"cloud_init": types.BoolValue(slices.Contains(advFeat, "cloud-init")),
"qemu_guest_agent": types.BoolValue(slices.Contains(advFeat, "qemu-guest-agent")),
"uefi_boot": types.BoolValue(slices.Contains(advFeat, "uefi-boot")),
})
if diags.HasError() {
data.AdvancedFeatures = resources.NewAdvancedFeaturesValueUnknown()
}
publicIpv4Addresses := []string{}
privateIpv4Addresses := []string{}
@@ -95,7 +95,7 @@ func (r *serverFirewallRulesResource) Create(ctx context.Context, req resource.C
}
tflog.Debug(ctx, fmt.Sprintf("Creating server firewall rules: server_id=%s", data.ServerId.String()))
serverResp, err := r.bc.client.PostServersServerIdActionsChangeAdvancedFirewallRulesWithResponse(
fwResp, err := r.bc.client.PostServersServerIdActionsChangeAdvancedFirewallRulesWithResponse(
ctx,
data.ServerId.ValueInt64(),
binarylane.PostServersServerIdActionsChangeAdvancedFirewallRulesJSONRequestBody{
@@ -109,10 +109,15 @@ func (r *serverFirewallRulesResource) Create(ctx context.Context, req resource.C
)
return
}
if serverResp.StatusCode() != http.StatusOK {
if fwResp.StatusCode() == http.StatusNotFound {
tflog.Warn(ctx, fmt.Sprintf("Server firewall rules not found, removing from state: server_id=%s", data.ServerId.String()))
resp.State.RemoveResource(ctx)
return
}
if fwResp.StatusCode() != http.StatusOK {
resp.Diagnostics.AddError(
"Unexpected HTTP status code creating server firewall rules",
fmt.Sprintf("Received %s creating server firewall rules: server_id=%s. Details: %s", serverResp.Status(), data.ServerId.String(), serverResp.Body))
fmt.Sprintf("Received %s creating server firewall rules: server_id=%s. Details: %s", fwResp.Status(), data.ServerId.String(), fwResp.Body))
return
}
+328 -97
View File
@@ -2,6 +2,7 @@ package provider
import (
"context"
"encoding/json"
"fmt"
"net/http"
"slices"
@@ -53,11 +54,10 @@ type serverResource struct {
type serverResourceModel struct {
serverDataModel
PublicIpv4Count types.Int32 `tfsdk:"public_ipv4_count"`
SourceAndDestinationCheck types.Bool `tfsdk:"source_and_destination_check"`
Password types.String `tfsdk:"password"`
PasswordChangeSupported types.Bool `tfsdk:"password_change_supported"`
Timeouts timeouts.Value `tfsdk:"timeouts"`
PublicIpv4Count types.Int32 `tfsdk:"public_ipv4_count"`
Password types.String `tfsdk:"password"`
PasswordChangeSupported types.Bool `tfsdk:"password_change_supported"`
Timeouts timeouts.Value `tfsdk:"timeouts"`
}
func (d *serverResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
@@ -82,12 +82,12 @@ func (r *serverResource) Metadata(ctx context.Context, req resource.MetadataRequ
resp.TypeName = req.ProviderTypeName + "_server"
}
func (r *serverResource) Schema(ctx context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = resources.ServerResourceSchema(ctx)
func serverSchema(ctx context.Context) schema.Schema {
s := resources.ServerResourceSchema(ctx)
// Overrides
id := resp.Schema.Attributes["id"]
resp.Schema.Attributes["id"] = &schema.Int64Attribute{
id := s.Attributes["id"]
s.Attributes["id"] = &schema.Int64Attribute{
Description: id.GetDescription(),
MarkdownDescription: id.GetMarkdownDescription(),
// read only
@@ -100,8 +100,8 @@ func (r *serverResource) Schema(ctx context.Context, _ resource.SchemaRequest, r
}
imageDescription := "The slug of the selected operating system, such as `debian-12`. You can fetch a full list of images from the BinaryLane API."
image := resp.Schema.Attributes["image"]
resp.Schema.Attributes["image"] = &schema.StringAttribute{
image := s.Attributes["image"]
s.Attributes["image"] = &schema.StringAttribute{
Description: imageDescription,
MarkdownDescription: imageDescription,
Required: image.IsRequired(),
@@ -113,7 +113,7 @@ func (r *serverResource) Schema(ctx context.Context, _ resource.SchemaRequest, r
}
backupsDescription := "If `true` this will enable two daily backups for the server. By default, backups are disabled."
resp.Schema.Attributes["backups"] = &schema.BoolAttribute{
s.Attributes["backups"] = &schema.BoolAttribute{
Description: backupsDescription,
MarkdownDescription: backupsDescription,
Optional: true,
@@ -121,24 +121,24 @@ func (r *serverResource) Schema(ctx context.Context, _ resource.SchemaRequest, r
Default: booldefault.StaticBool(false), // Add default to backups
}
user_data := resp.Schema.Attributes["user_data"]
resp.Schema.Attributes["user_data"] = &schema.StringAttribute{
user_data := s.Attributes["user_data"]
s.Attributes["user_data"] = &schema.StringAttribute{
Description: user_data.GetDescription(),
MarkdownDescription: user_data.GetMarkdownDescription(),
Optional: true, // Optional as not all servers have an initialization script
Computed: false, // User defined
}
vpcId := resp.Schema.Attributes["vpc_id"]
resp.Schema.Attributes["vpc_id"] = &schema.Int64Attribute{
vpcId := s.Attributes["vpc_id"]
s.Attributes["vpc_id"] = &schema.Int64Attribute{
Description: vpcId.GetDescription(),
MarkdownDescription: vpcId.GetMarkdownDescription(),
Optional: vpcId.IsOptional(),
Computed: false, // vpc_id is not computed, defined at creation
}
portBlocking := resp.Schema.Attributes["port_blocking"]
resp.Schema.Attributes["port_blocking"] = &schema.BoolAttribute{
portBlocking := s.Attributes["port_blocking"]
s.Attributes["port_blocking"] = &schema.BoolAttribute{
Description: portBlocking.GetDescription(),
MarkdownDescription: portBlocking.GetMarkdownDescription(),
Optional: portBlocking.IsOptional(),
@@ -146,8 +146,8 @@ func (r *serverResource) Schema(ctx context.Context, _ resource.SchemaRequest, r
Default: booldefault.StaticBool(true), // Add default to port_blocking
}
region := resp.Schema.Attributes["region"].(schema.StringAttribute)
resp.Schema.Attributes["region"] = &schema.StringAttribute{
region := s.Attributes["region"].(schema.StringAttribute)
s.Attributes["region"] = &schema.StringAttribute{
Description: region.GetDescription(),
MarkdownDescription: region.GetMarkdownDescription(),
Optional: region.IsOptional(),
@@ -159,8 +159,8 @@ func (r *serverResource) Schema(ctx context.Context, _ resource.SchemaRequest, r
},
}
sshKeys := resp.Schema.Attributes["ssh_keys"]
resp.Schema.Attributes["ssh_keys"] = &schema.ListAttribute{
sshKeys := s.Attributes["ssh_keys"]
s.Attributes["ssh_keys"] = &schema.ListAttribute{
ElementType: types.Int64Type,
Description: sshKeys.GetMarkdownDescription(),
MarkdownDescription: sshKeys.GetDescription(),
@@ -173,8 +173,8 @@ func (r *serverResource) Schema(ctx context.Context, _ resource.SchemaRequest, r
userDataDescription := "A script or cloud-config YAML file to configure the server. Can only be specified if the OS image supports UserData (i.e. not Windows)." +
" See more: https://cloudinit.readthedocs.io/en/latest/explanation/format.html#user-data-script"
userData := resp.Schema.Attributes["user_data"]
resp.Schema.Attributes["user_data"] = &schema.StringAttribute{
userData := s.Attributes["user_data"]
s.Attributes["user_data"] = &schema.StringAttribute{
Description: userDataDescription,
MarkdownDescription: userDataDescription,
Required: userData.IsRequired(),
@@ -190,7 +190,7 @@ func (r *serverResource) Schema(ctx context.Context, _ resource.SchemaRequest, r
"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."
resp.Schema.Attributes["password"] = &schema.StringAttribute{
s.Attributes["password"] = &schema.StringAttribute{
Description: pwDescription,
MarkdownDescription: pwDescription,
Optional: true, // Password optional, if not set will be emailed to user
@@ -199,7 +199,7 @@ func (r *serverResource) Schema(ctx context.Context, _ resource.SchemaRequest, r
}
publicIpv4CountDescription := "The number of public IPv4 addresses to assign to the server."
resp.Schema.Attributes["public_ipv4_count"] = &schema.Int32Attribute{
s.Attributes["public_ipv4_count"] = &schema.Int32Attribute{
Description: publicIpv4CountDescription,
MarkdownDescription: publicIpv4CountDescription,
Required: true,
@@ -212,7 +212,7 @@ func (r *serverResource) Schema(ctx context.Context, _ resource.SchemaRequest, r
}
publicIpv4AddressesDescription := "The public IPv4 addresses assigned to the server."
resp.Schema.Attributes["public_ipv4_addresses"] = &schema.ListAttribute{
s.Attributes["public_ipv4_addresses"] = &schema.ListAttribute{
Description: publicIpv4AddressesDescription,
MarkdownDescription: publicIpv4AddressesDescription,
ElementType: types.StringType,
@@ -229,7 +229,7 @@ func (r *serverResource) Schema(ctx context.Context, _ resource.SchemaRequest, r
"to incorrect network configuration. When `source_and_destination_check` is `false`, your Cloud Server will be able " +
"to send and receive packets addressed to any server. This is typically used when you want to use " +
"your Cloud Server as a VPN endpoint, a NAT server to provide internet access, or IP forwarding."
resp.Schema.Attributes["source_and_destination_check"] = &schema.BoolAttribute{
s.Attributes["source_and_destination_check"] = &schema.BoolAttribute{
Description: sourceDestCheckDescription,
MarkdownDescription: sourceDestCheckDescription,
Optional: true,
@@ -243,7 +243,7 @@ func (r *serverResource) Schema(ctx context.Context, _ resource.SchemaRequest, r
}
privateIpv4AddressesDescription := "The private IPv4 addresses assigned to the server."
resp.Schema.Attributes["private_ipv4_addresses"] = &schema.ListAttribute{
s.Attributes["private_ipv4_addresses"] = &schema.ListAttribute{
Description: privateIpv4AddressesDescription,
MarkdownDescription: privateIpv4AddressesDescription,
ElementType: types.StringType,
@@ -256,7 +256,7 @@ func (r *serverResource) Schema(ctx context.Context, _ resource.SchemaRequest, r
},
}
resp.Schema.Attributes["permalink"] = &schema.StringAttribute{
s.Attributes["permalink"] = &schema.StringAttribute{
Description: "A randomly generated two-word identifier assigned to servers in regions that support this feature",
MarkdownDescription: "A randomly generated two-word identifier assigned to servers in regions that support this feature",
// read only
@@ -271,7 +271,7 @@ func (r *serverResource) Schema(ctx context.Context, _ resource.SchemaRequest, r
pwChangeDescription := "If this is true then the `password` attribute can be changed with Terraform. " +
"If this is false then the `password` attribute can only be replaced with a null/empty value, which will clear " +
"the root/administrator password allowing the password to be changed via the web console."
resp.Schema.Attributes["password_change_supported"] = &schema.BoolAttribute{
s.Attributes["password_change_supported"] = &schema.BoolAttribute{
Description: pwChangeDescription,
MarkdownDescription: pwChangeDescription,
// read only
@@ -293,7 +293,7 @@ func (r *serverResource) Schema(ctx context.Context, _ resource.SchemaRequest, r
- \> 16384 MB must be a multiple of 2048
- \> 24576 MB must be a multiple of 4096`
resp.Schema.Attributes["memory"] = &schema.Int32Attribute{
s.Attributes["memory"] = &schema.Int32Attribute{
Description: memoryDescription + memoryValidValues,
MarkdownDescription: memoryDescription + memoryValidValuesMarkdown,
Optional: true,
@@ -316,7 +316,7 @@ func (r *serverResource) Schema(ctx context.Context, _ resource.SchemaRequest, r
- \> 60 GB must be a multiple of 10
- \> 200 GB must be a multiple of 100`
resp.Schema.Attributes["disk"] = &schema.Int32Attribute{
s.Attributes["disk"] = &schema.Int32Attribute{
Description: diskDescription + diskValidValues,
MarkdownDescription: diskDescription + diskValidValuesMarkdown,
Optional: true,
@@ -330,15 +330,21 @@ func (r *serverResource) Schema(ctx context.Context, _ resource.SchemaRequest, r
},
}
resp.Schema.Attributes["timeouts"] =
s.Attributes["timeouts"] =
timeouts.Attributes(ctx, timeouts.Opts{
Create: true,
Update: true,
})
return s
}
func (r *serverResource) Schema(ctx context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = serverSchema(ctx)
}
func (r *serverResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
var plan, state serverResourceModel
var config, plan, state serverResourceModel
if req.Plan.Raw.IsNull() {
// Destruction plan, no modification needed
@@ -346,6 +352,7 @@ func (r *serverResource) ModifyPlan(ctx context.Context, req resource.ModifyPlan
}
// Read Terraform plan data into the model
resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
if resp.Diagnostics.HasError() {
return
@@ -415,16 +422,79 @@ func (r *serverResource) ModifyPlan(ctx context.Context, req resource.ModifyPlan
plan.Disk = state.Disk
}
if isAdvFeatChanged(&config.AdvancedFeatures, &state.AdvancedFeatures) {
advFeatResp, err := r.bc.client.GetServersServerIdAvailableAdvancedFeaturesWithResponse(ctx, state.Id.ValueInt64())
if err != nil {
resp.Diagnostics.AddError(
fmt.Sprintf("Error fetching available advanced features for server: id=%s", state.Id.String()),
err.Error(),
)
} else if advFeatResp.StatusCode() != http.StatusOK {
resp.Diagnostics.AddError(
"Unexpected HTTP status code fetching available advanced features for server",
fmt.Sprintf("Received %s fetching available advanced features for server: id=%s. Details: %s", advFeatResp.Status(), state.Id.String(), advFeatResp.Body))
} else {
debugAdvFeatResp, _ := json.Marshal(advFeatResp.JSON200)
tflog.Debug(ctx, fmt.Sprintf("Recieved response for available advanced features: %s", debugAdvFeatResp))
availableAdvFeat := *advFeatResp.JSON200.AvailableAdvancedServerFeatures.AdvancedFeatures
if plan.AdvancedFeatures.EmulatedHyperv.ValueBool() && !slices.Contains(availableAdvFeat, "emulated-hyperv") {
resp.Diagnostics.AddAttributeError(
path.Root("advanced_features").AtName("emulated_hyperv"),
"Emulated Hyper-V not available",
fmt.Sprintf("Emulated Hyper-V is not available for server %s", state.Name.String()),
)
} else if plan.AdvancedFeatures.EmulatedDevices.ValueBool() && !slices.Contains(availableAdvFeat, "emulated-devices") {
resp.Diagnostics.AddAttributeError(
path.Root("advanced_features").AtName("emulated_devices"),
"Emulated Devices not available",
fmt.Sprintf("Emulated Devices is not available for server %s", state.Name.String()),
)
} else if plan.AdvancedFeatures.EmulatedTpm.ValueBool() && !slices.Contains(availableAdvFeat, "emulated-tpm") {
resp.Diagnostics.AddAttributeError(
path.Root("advanced_features").AtName("emulated_tpm"),
"Emulated TPM not available",
fmt.Sprintf("Emulated TPM is not available for server %s", state.Name.String()),
)
} else if plan.AdvancedFeatures.NestedVirt.ValueBool() && !slices.Contains(availableAdvFeat, "nested-virt") {
resp.Diagnostics.AddAttributeError(
path.Root("advanced_features").AtName("nested_virt"),
"Nested Virtualization not available",
fmt.Sprintf("Nested Virtualization is not available for server %s", state.Name.String()),
)
} else if plan.AdvancedFeatures.DriverDisk.ValueBool() && !slices.Contains(availableAdvFeat, "driver-disk") {
resp.Diagnostics.AddAttributeError(
path.Root("advanced_features").AtName("driver_disk"),
"Driver Disk not available",
fmt.Sprintf("Driver Disk is not available for server %s", state.Name.String()),
)
} else if plan.AdvancedFeatures.UnsetUuid.ValueBool() && !slices.Contains(availableAdvFeat, "unset-uuid") {
resp.Diagnostics.AddAttributeError(
path.Root("advanced_features").AtName("unset_uuid"),
"Unset UUID not available",
fmt.Sprintf("Unset UUID is not available for server %s", state.Name.String()),
)
} else if plan.AdvancedFeatures.LocalRtc.ValueBool() && !slices.Contains(availableAdvFeat, "local-rtc") {
resp.Diagnostics.AddAttributeError(
path.Root("advanced_features").AtName("local_rtc"),
"Local RTC not available",
fmt.Sprintf("Local RTC is not available for server %s", state.Name.String()),
)
}
}
}
// Save data into Terraform state
resp.Diagnostics.Append(resp.Plan.Set(ctx, &plan)...)
}
func (r *serverResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var data serverResourceModel
var config, data serverResourceModel
// Read Terraform plan data into the model
diags := req.Plan.Get(ctx, &data)
resp.Diagnostics.Append(diags...)
resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}
@@ -524,6 +594,26 @@ func (r *serverResource) Create(ctx context.Context, req resource.CreateRequest,
serverRespSourceDestCheck := types.BoolPointerValue(serverResp.JSON200.Server.Networks.SourceAndDestinationCheck)
data.SourceAndDestinationCheck = serverRespSourceDestCheck
advFeat := *serverResp.JSON200.Server.AdvancedFeatures.EnabledAdvancedFeatures
data.AdvancedFeatures, diags = resources.NewAdvancedFeaturesValue(
resources.AdvancedFeaturesValue{}.AttributeTypes(ctx),
map[string]attr.Value{
"emulated_hyperv": types.BoolValue(slices.Contains(advFeat, "emulated-hyperv")),
"emulated_devices": types.BoolValue(slices.Contains(advFeat, "emulated-devices")),
"nested_virt": types.BoolValue(slices.Contains(advFeat, "nested-virt")),
"driver_disk": types.BoolValue(slices.Contains(advFeat, "driver-disk")),
"unset_uuid": types.BoolValue(slices.Contains(advFeat, "unset-uuid")),
"local_rtc": types.BoolValue(slices.Contains(advFeat, "local-rtc")),
"emulated_tpm": types.BoolValue(slices.Contains(advFeat, "emulated-tpm")),
"cloud_init": types.BoolValue(slices.Contains(advFeat, "cloud-init")),
"qemu_guest_agent": types.BoolValue(slices.Contains(advFeat, "qemu-guest-agent")),
"uefi_boot": types.BoolValue(slices.Contains(advFeat, "uefi-boot")),
})
if diags.HasError() {
resp.Diagnostics.Append(diags...)
data.AdvancedFeatures = resources.NewAdvancedFeaturesValueUnknown()
}
publicIpv4Addresses := []string{}
privateIpv4Addresses := []string{}
for _, v4address := range serverResp.JSON200.Server.Networks.V4 {
@@ -540,6 +630,21 @@ func (r *serverResource) Create(ctx context.Context, req resource.CreateRequest,
// Save data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}
// Update advanced features
err = r.updateAdvancedFeatures(ctx, data.Id.ValueInt64(), &config.AdvancedFeatures, &data.AdvancedFeatures)
if err != nil {
resp.Diagnostics.AddError("Error updating advanced features", err.Error())
}
// Save data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}
// Update source_and_destination_check if needed
if plannedSourceDestCheck.Equal(types.BoolPointerValue(Pointer(false))) {
@@ -551,6 +656,11 @@ func (r *serverResource) Create(ctx context.Context, req resource.CreateRequest,
data.SourceAndDestinationCheck = plannedSourceDestCheck
}
// One extra read to check the final state of enabled_advanced_features, needed because
// some flags (like "cloud-init") are not set until the server is fully created. See #13
diag := r.fetchServerResourceState(ctx, &data)
resp.Diagnostics.Append(diag...)
// Save data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}
@@ -567,24 +677,7 @@ func (r *serverResource) Read(ctx context.Context, req resource.ReadRequest, res
// Read API call logic
tflog.Debug(ctx, fmt.Sprintf("Reading server: id=%s, name=%s", data.Id.String(), data.Name.ValueString()))
serverResp, err := r.bc.client.GetServersServerIdWithResponse(ctx, data.Id.ValueInt64())
if err != nil {
resp.Diagnostics.AddError(
fmt.Sprintf("Error reading server: id=%s, name=%s", data.Id.String(), data.Name.ValueString()),
err.Error(),
)
return
}
if serverResp.StatusCode() != http.StatusOK {
resp.Diagnostics.AddError(
fmt.Sprintf("Unexpected HTTP status code %s reading server: name=%s, id=%s", serverResp.Status(), data.Name.ValueString(), data.Id.String()),
string(serverResp.Body),
)
return
}
diag := setServerResourceState(ctx, &data, serverResp.JSON200)
diag := r.fetchServerResourceState(ctx, &data)
resp.Diagnostics.Append(diag...)
// Get user data script
@@ -610,9 +703,11 @@ 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 plan, state serverResourceModel
var diag diag.Diagnostics
var config, plan, state serverResourceModel
// Read Terraform plan data into the model
resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
if resp.Diagnostics.HasError() {
@@ -632,23 +727,7 @@ func (r *serverResource) Update(ctx context.Context, req resource.UpdateRequest,
return
}
serverResp, err := r.bc.client.GetServersServerIdWithResponse(ctx, state.Id.ValueInt64())
if err != nil {
resp.Diagnostics.AddError(
fmt.Sprintf("Error reading server: id=%s, name=%s", state.Id.String(), state.Name.ValueString()),
err.Error(),
)
return
}
if serverResp.StatusCode() != http.StatusOK {
resp.Diagnostics.AddError(
fmt.Sprintf("Unexpected HTTP status code %s reading server: name=%s, id=%s", serverResp.Status(), state.Name.ValueString(), state.Id.String()),
string(serverResp.Body),
)
return
}
diag := setServerResourceState(ctx, &state, serverResp.JSON200)
diag := r.fetchServerResourceState(ctx, &state)
resp.Diagnostics.Append(diag...)
// Save updated data into Terraform state
@@ -897,6 +976,17 @@ func (r *serverResource) Update(ctx context.Context, req resource.UpdateRequest,
}
}
err := r.updateAdvancedFeatures(ctx, state.Id.ValueInt64(), &config.AdvancedFeatures, &state.AdvancedFeatures)
if err != nil {
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
}
// Check source_and_destination_check
if !plan.SourceAndDestinationCheck.Equal(state.SourceAndDestinationCheck) {
if !plan.SourceAndDestinationCheck.IsNull() {
@@ -1140,31 +1230,68 @@ func (r *serverResource) updateSourceDestCheck(
return nil
}
func setServerResourceState(ctx context.Context, data *serverResourceModel, serverResp *binarylane.ServerResponse) diag.Diagnostics {
func (r *serverResource) fetchServerResourceState(ctx context.Context, state *serverResourceModel) diag.Diagnostics {
var diags diag.Diagnostics
data.Id = types.Int64Value(*serverResp.Server.Id)
data.Name = types.StringValue(*serverResp.Server.Name)
data.Image = types.StringValue(*serverResp.Server.Image.Slug)
data.Region = types.StringValue(*serverResp.Server.Region.Slug)
data.Size = types.StringValue(*serverResp.Server.Size.Slug)
data.Backups = types.BoolValue(serverResp.Server.NextBackupWindow != nil)
data.PortBlocking = types.BoolValue(serverResp.Server.Networks.PortBlocking)
data.VpcId = types.Int64PointerValue(serverResp.Server.VpcId)
data.Permalink = types.StringValue(*serverResp.Server.Permalink)
data.PasswordChangeSupported = types.BoolValue(*serverResp.Server.PasswordChangeSupported)
data.SourceAndDestinationCheck = types.BoolPointerValue(serverResp.Server.Networks.SourceAndDestinationCheck)
data.Memory = types.Int32Value(*serverResp.Server.Memory)
data.Disk = types.Int32Value(*serverResp.Server.Disk)
data.Backups = types.BoolValue(serverResp.Server.NextBackupWindow != nil)
serverResp, err := r.bc.client.GetServersServerIdWithResponse(ctx, state.Id.ValueInt64())
if err != nil {
return diag.Diagnostics{
diag.NewErrorDiagnostic(
fmt.Sprintf("Error reading server: id=%s, name=%s", state.Id.String(), state.Name.ValueString()),
err.Error(),
),
}
}
if serverResp.StatusCode() != http.StatusOK {
return diag.Diagnostics{
diag.NewErrorDiagnostic(
fmt.Sprintf("Unexpected HTTP status code %s reading server: name=%s, id=%s", serverResp.Status(), state.Name.ValueString(), state.Id.String()),
string(serverResp.Body),
),
}
}
state.Id = types.Int64Value(*serverResp.JSON200.Server.Id)
state.Name = types.StringValue(*serverResp.JSON200.Server.Name)
state.Image = types.StringValue(*serverResp.JSON200.Server.Image.Slug)
state.Region = types.StringValue(*serverResp.JSON200.Server.Region.Slug)
state.Size = types.StringValue(*serverResp.JSON200.Server.Size.Slug)
state.Backups = types.BoolValue(serverResp.JSON200.Server.NextBackupWindow != nil)
state.PortBlocking = types.BoolValue(serverResp.JSON200.Server.Networks.PortBlocking)
state.VpcId = types.Int64PointerValue(serverResp.JSON200.Server.VpcId)
state.Permalink = types.StringValue(*serverResp.JSON200.Server.Permalink)
state.PasswordChangeSupported = types.BoolValue(*serverResp.JSON200.Server.PasswordChangeSupported)
state.SourceAndDestinationCheck = types.BoolPointerValue(serverResp.JSON200.Server.Networks.SourceAndDestinationCheck)
state.Memory = types.Int32Value(*serverResp.JSON200.Server.Memory)
state.Disk = types.Int32Value(*serverResp.JSON200.Server.Disk)
state.Backups = types.BoolValue(serverResp.JSON200.Server.NextBackupWindow != nil)
advFeat := *serverResp.JSON200.Server.AdvancedFeatures.EnabledAdvancedFeatures
state.AdvancedFeatures, diags = resources.NewAdvancedFeaturesValue(
resources.AdvancedFeaturesValue{}.AttributeTypes(ctx),
map[string]attr.Value{
"emulated_hyperv": types.BoolValue(slices.Contains(advFeat, "emulated-hyperv")),
"emulated_devices": types.BoolValue(slices.Contains(advFeat, "emulated-devices")),
"nested_virt": types.BoolValue(slices.Contains(advFeat, "nested-virt")),
"driver_disk": types.BoolValue(slices.Contains(advFeat, "driver-disk")),
"unset_uuid": types.BoolValue(slices.Contains(advFeat, "unset-uuid")),
"local_rtc": types.BoolValue(slices.Contains(advFeat, "local-rtc")),
"emulated_tpm": types.BoolValue(slices.Contains(advFeat, "emulated-tpm")),
"cloud_init": types.BoolValue(slices.Contains(advFeat, "cloud-init")),
"qemu_guest_agent": types.BoolValue(slices.Contains(advFeat, "qemu-guest-agent")),
"uefi_boot": types.BoolValue(slices.Contains(advFeat, "uefi-boot")),
})
if diags.HasError() {
state.AdvancedFeatures = resources.NewAdvancedFeaturesValueUnknown()
}
publicIpv4Addresses := []string{}
privateIpv4Addresses := []string{}
for _, v4address := range serverResp.Server.Networks.V4 {
for _, v4address := range serverResp.JSON200.Server.Networks.V4 {
if v4address.Type == "public" {
publicIpv4Addresses = append(publicIpv4Addresses, v4address.IpAddress)
} else {
} else if v4address.Type == "private" {
privateIpv4Addresses = append(privateIpv4Addresses, v4address.IpAddress)
}
}
@@ -1172,20 +1299,124 @@ func setServerResourceState(ctx context.Context, data *serverResourceModel, serv
tfPublicIpv4Addresses, diag := types.ListValueFrom(ctx, types.StringType, publicIpv4Addresses)
diags.Append(diag...)
if diag.HasError() {
data.PublicIpv4Addresses = types.ListUnknown(data.PublicIpv4Addresses.ElementType(ctx))
data.PublicIpv4Count = types.Int32Unknown()
state.PublicIpv4Addresses = types.ListUnknown(state.PublicIpv4Addresses.ElementType(ctx))
state.PublicIpv4Count = types.Int32Unknown()
} else {
data.PublicIpv4Addresses = tfPublicIpv4Addresses
data.PublicIpv4Count = types.Int32Value(int32(len(publicIpv4Addresses)))
state.PublicIpv4Addresses = tfPublicIpv4Addresses
state.PublicIpv4Count = types.Int32Value(int32(len(publicIpv4Addresses)))
}
tfPrivateIpv4Addresses, diag := types.ListValueFrom(ctx, types.StringType, privateIpv4Addresses)
diags.Append(diag...)
if diag.HasError() {
data.PrivateIPv4Addresses = types.ListUnknown(data.PrivateIPv4Addresses.ElementType(ctx))
state.PrivateIPv4Addresses = types.ListUnknown(state.PrivateIPv4Addresses.ElementType(ctx))
} else {
data.PrivateIPv4Addresses = tfPrivateIpv4Addresses
state.PrivateIPv4Addresses = tfPrivateIpv4Addresses
}
return diags
}
func isAdvFeatChanged(config *resources.AdvancedFeaturesValue, data *resources.AdvancedFeaturesValue) bool {
// Check if any of the writable advanced features have been modified by the user
return (!config.EmulatedHyperv.IsNull() && !config.EmulatedHyperv.Equal(data.EmulatedHyperv)) ||
(!config.EmulatedDevices.IsNull() && !config.EmulatedDevices.Equal(data.EmulatedDevices)) ||
(!config.EmulatedTpm.IsNull() && !config.EmulatedTpm.Equal(data.EmulatedTpm)) ||
(!config.NestedVirt.IsNull() && !config.NestedVirt.Equal(data.NestedVirt)) ||
(!config.DriverDisk.IsNull() && !config.DriverDisk.Equal(data.DriverDisk)) ||
(!config.UnsetUuid.IsNull() && !config.UnsetUuid.Equal(data.UnsetUuid)) ||
(!config.LocalRtc.IsNull() && !config.LocalRtc.Equal(data.LocalRtc))
}
func (r *serverResource) updateAdvancedFeatures(
ctx context.Context,
serverId int64,
config *resources.AdvancedFeaturesValue,
data *resources.AdvancedFeaturesValue,
) error {
// If none of the writable advanced features have been modified by the user, we can skip the update
if !isAdvFeatChanged(config, data) {
return nil
}
tflog.Info(ctx, fmt.Sprintf("Changing advanced features for server: server_id=%d", serverId))
enabledAdvancedFeatures := []string{}
// The enabled advanced features are flags that the user has configured, or are configured by default
emulatedHyperV := config.EmulatedHyperv.ValueBool() || config.EmulatedHyperv.IsNull() && data.EmulatedDevices.ValueBool()
if emulatedHyperV {
enabledAdvancedFeatures = append(enabledAdvancedFeatures, "emulated-hyperv")
}
emulatedDevices := config.EmulatedDevices.ValueBool() || config.EmulatedDevices.IsNull() && data.EmulatedDevices.ValueBool()
if emulatedDevices {
enabledAdvancedFeatures = append(enabledAdvancedFeatures, "emulated-devices")
}
emulatedTPM := config.EmulatedTpm.ValueBool() || config.EmulatedTpm.IsNull() && data.EmulatedTpm.ValueBool()
if emulatedTPM {
enabledAdvancedFeatures = append(enabledAdvancedFeatures, "emulated-tpm")
}
nestedVirt := config.NestedVirt.ValueBool() || config.NestedVirt.IsNull() && data.NestedVirt.ValueBool()
if nestedVirt {
enabledAdvancedFeatures = append(enabledAdvancedFeatures, "nested-virt")
}
driverDisk := config.DriverDisk.ValueBool() || config.DriverDisk.IsNull() && data.DriverDisk.ValueBool()
if driverDisk {
enabledAdvancedFeatures = append(enabledAdvancedFeatures, "driver-disk")
}
unsetUUID := config.UnsetUuid.ValueBool() || config.UnsetUuid.IsNull() && data.UnsetUuid.ValueBool()
if unsetUUID {
enabledAdvancedFeatures = append(enabledAdvancedFeatures, "unset-uuid")
}
localRTC := config.LocalRtc.ValueBool() || config.LocalRtc.IsNull() && data.LocalRtc.ValueBool()
if localRTC {
enabledAdvancedFeatures = append(enabledAdvancedFeatures, "local-rtc")
}
// Include the current value of read-only advanced features in the payload to the server
cloudInit := data.CloudInit.ValueBool()
if cloudInit {
enabledAdvancedFeatures = append(enabledAdvancedFeatures, "cloud-init")
}
qemuGuestAgent := data.QemuGuestAgent.ValueBool()
if qemuGuestAgent {
enabledAdvancedFeatures = append(enabledAdvancedFeatures, "qemu-guest-agent")
}
uefiBoot := data.UefiBoot.ValueBool()
if uefiBoot {
enabledAdvancedFeatures = append(enabledAdvancedFeatures, "uefi-boot")
}
resp, err := r.bc.client.PostServersServerIdActionsChangeAdvancedFeaturesWithResponse(
ctx,
serverId,
binarylane.PostServersServerIdActionsChangeAdvancedFeaturesJSONRequestBody{
Type: "change_advanced_features",
EnabledAdvancedFeatures: &enabledAdvancedFeatures,
},
)
if err != nil {
return fmt.Errorf("error changing advanced features for server: server_id=%d, error: %w", serverId, err)
}
if resp.StatusCode() != http.StatusOK {
return fmt.Errorf("unexpected HTTP status code updating advanced features for server: server_id=%d, details: %s", serverId, resp.Body)
}
err = r.waitForServerAction(ctx, serverId, *resp.JSON200.Action.Id)
if err != nil {
return fmt.Errorf("failed to confirm advanced features for server was successful: %w", err)
}
data.EmulatedHyperv = types.BoolValue(emulatedHyperV)
data.EmulatedDevices = types.BoolValue(emulatedDevices)
data.EmulatedTpm = types.BoolValue(emulatedTPM)
data.NestedVirt = types.BoolValue(nestedVirt)
data.DriverDisk = types.BoolValue(driverDisk)
data.UnsetUuid = types.BoolValue(unsetUUID)
data.LocalRtc = types.BoolValue(localRTC)
data.CloudInit = types.BoolValue(cloudInit)
data.QemuGuestAgent = types.BoolValue(qemuGuestAgent)
data.UefiBoot = types.BoolValue(uefiBoot)
return nil
}
+24
View File
@@ -99,6 +99,16 @@ echo "Hello World" > /var/tmp/output.txt
resource.TestCheckResourceAttrSet("binarylane_server.test", "permalink"),
resource.TestCheckResourceAttr("binarylane_server.test", "source_and_destination_check", "false"),
resource.TestCheckResourceAttr("binarylane_server.test", "backups", "true"),
resource.TestCheckResourceAttr("binarylane_server.test", "advanced_features.emulated_hyperv", "false"),
resource.TestCheckResourceAttr("binarylane_server.test", "advanced_features.emulated_devices", "false"),
resource.TestCheckResourceAttr("binarylane_server.test", "advanced_features.nested_virt", "false"),
resource.TestCheckResourceAttr("binarylane_server.test", "advanced_features.driver_disk", "false"),
resource.TestCheckResourceAttr("binarylane_server.test", "advanced_features.unset_uuid", "false"),
resource.TestCheckResourceAttr("binarylane_server.test", "advanced_features.local_rtc", "false"),
resource.TestCheckResourceAttr("binarylane_server.test", "advanced_features.emulated_tpm", "false"),
resource.TestCheckResourceAttr("binarylane_server.test", "advanced_features.cloud_init", "true"),
resource.TestCheckResourceAttr("binarylane_server.test", "advanced_features.qemu_guest_agent", "false"),
resource.TestCheckResourceAttr("binarylane_server.test", "advanced_features.uefi_boot", "false"),
// Verify data source values
resource.TestCheckResourceAttrPair("data.binarylane_server.test", "id", "binarylane_server.test", "id"),
@@ -115,6 +125,16 @@ echo "Hello World" > /var/tmp/output.txt
resource.TestCheckResourceAttr("data.binarylane_server.test", "disk", "20"),
resource.TestCheckResourceAttr("data.binarylane_server.test", "backups", "true"),
resource.TestCheckResourceAttr("data.binarylane_server.test", "port_blocking", "false"),
resource.TestCheckResourceAttr("data.binarylane_server.test", "advanced_features.emulated_hyperv", "false"),
resource.TestCheckResourceAttr("data.binarylane_server.test", "advanced_features.emulated_devices", "false"),
resource.TestCheckResourceAttr("data.binarylane_server.test", "advanced_features.nested_virt", "false"),
resource.TestCheckResourceAttr("data.binarylane_server.test", "advanced_features.driver_disk", "false"),
resource.TestCheckResourceAttr("data.binarylane_server.test", "advanced_features.unset_uuid", "false"),
resource.TestCheckResourceAttr("data.binarylane_server.test", "advanced_features.local_rtc", "false"),
resource.TestCheckResourceAttr("data.binarylane_server.test", "advanced_features.emulated_tpm", "false"),
resource.TestCheckResourceAttr("data.binarylane_server.test", "advanced_features.cloud_init", "true"),
resource.TestCheckResourceAttr("data.binarylane_server.test", "advanced_features.qemu_guest_agent", "false"),
resource.TestCheckResourceAttr("data.binarylane_server.test", "advanced_features.uefi_boot", "false"),
),
},
// Test import by ID
@@ -162,6 +182,9 @@ resource "binarylane_server" "test" {
vpc_id = null
public_ipv4_count = 0
ssh_keys = [binarylane_ssh_key.updated.id]
advanced_features = {
emulated_hyperv = true
}
# source_and_destination_check = null # defaults to null
# backups = false # defaults to false
@@ -186,6 +209,7 @@ EOT
resource.TestCheckNoResourceAttr("binarylane_server.test", "vpc_id"),
resource.TestCheckResourceAttr("binarylane_server.test", "ssh_keys.#", "1"),
resource.TestCheckResourceAttrPair("binarylane_server.test", "ssh_keys.0", "binarylane_ssh_key.updated", "id"),
resource.TestCheckResourceAttr("binarylane_server.test", "advanced_features.emulated_hyperv", "true"),
resource.TestCheckNoResourceAttr("binarylane_server.test", "source_and_destination_check"),
resource.TestCheckResourceAttr("binarylane_server.test", "backups", "false"),
resource.TestCheckResourceAttr("binarylane_server.test", "port_blocking", "true"),
+6
View File
@@ -15,6 +15,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
)
// Ensure the implementation satisfies the expected interfaces.
@@ -123,6 +124,11 @@ func (r *sshKeyResource) Create(ctx context.Context, req resource.CreateRequest,
)
return
}
if sshResp.StatusCode() == http.StatusNotFound {
tflog.Warn(ctx, fmt.Sprintf("SSH Key not found, removing from state: name=%s", data.Name.String()))
resp.State.RemoveResource(ctx)
return
}
if sshResp.StatusCode() != http.StatusOK {
resp.Diagnostics.AddError(
"Unexpected HTTP status code creating SSH key",
+14 -1
View File
@@ -125,6 +125,7 @@ func convertResourceAttrToDataSourceAttr(name string, attribute r_schema.Attribu
MarkdownDescription: attribute.GetMarkdownDescription(),
DeprecationMessage: attribute.GetDeprecationMessage(),
}, nil
default:
if t, isList := attribute.(r_schema.ListNestedAttribute); isList {
nestedObjectAttrs := make(map[string]d_schema.Attribute)
@@ -164,7 +165,6 @@ func convertResourceAttrToDataSourceAttr(name string, attribute r_schema.Attribu
DeprecationMessage: attribute.GetDeprecationMessage(),
}, nil
}
if t, isObject := attribute.(r_schema.SingleNestedAttribute); isObject {
attributeTypes := make(map[string]attr.Type, len(t.GetAttributes()))
for name, attribute := range t.GetAttributes() {
@@ -184,6 +184,19 @@ func convertResourceAttrToDataSourceAttr(name string, attribute r_schema.Attribu
}, nil
}
if t, isObject := attribute.GetType().(types.ObjectType); isObject {
return d_schema.ObjectAttribute{
AttributeTypes: t.AttrTypes,
Description: attribute.GetDescription(),
Required: required,
Optional: optional,
Computed: !required,
Sensitive: attribute.IsSensitive(),
MarkdownDescription: attribute.GetMarkdownDescription(),
DeprecationMessage: attribute.GetDeprecationMessage(),
}, nil
}
return nil, fmt.Errorf("conversion of attribute type is not implemented: name=%s, type=%s", name, attribute.GetType())
}
}
+5
View File
@@ -130,6 +130,11 @@ func (r *vpcResource) Read(ctx context.Context, req resource.ReadRequest, resp *
)
return
}
if vpcResp.StatusCode() == http.StatusNotFound {
tflog.Warn(ctx, fmt.Sprintf("VPC not found, removing from state: id=%d", data.Id.ValueInt64()))
resp.State.RemoveResource(ctx)
return
}
if vpcResp.StatusCode() != http.StatusOK {
resp.Diagnostics.AddError(
"Unexpected HTTP status code reading VPC",
@@ -17,6 +17,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
"github.com/hashicorp/terraform-plugin-log/tflog"
)
var (
@@ -123,6 +124,11 @@ func (r *vpcRouteEntriesResource) Read(ctx context.Context, req resource.ReadReq
)
return
}
if vpcResp.StatusCode() == http.StatusNotFound {
tflog.Warn(ctx, fmt.Sprintf("VPC route entries not found, removing from state: vpc_id=%d", data.VpcId.ValueInt64()))
resp.State.RemoveResource(ctx)
return
}
if vpcResp.StatusCode() != http.StatusOK {
resp.Diagnostics.AddError(
"Unexpected HTTP status code reading VPC route entries",
+904 -10
View File
@@ -4,9 +4,15 @@ package resources
import (
"context"
"fmt"
"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/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
"github.com/hashicorp/terraform-plugin-go/tftypes"
"strings"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
)
@@ -14,6 +20,74 @@ import (
func ServerResourceSchema(ctx context.Context) schema.Schema {
return schema.Schema{
Attributes: map[string]schema.Attribute{
"advanced_features": schema.SingleNestedAttribute{
Attributes: map[string]schema.Attribute{
"cloud_init": schema.BoolAttribute{
Computed: true,
Description: "When this option is enabled the Cloud Server will be provided a datasource for the cloud-init service.",
MarkdownDescription: "When this option is enabled the Cloud Server will be provided a datasource for the cloud-init service.",
},
"driver_disk": schema.BoolAttribute{
Optional: true,
Computed: true,
Description: "When this option is enabled a copy of the KVM driver disc for Windows (\"virtio-win.iso\") will be attached to your server as a virtual CD. This option can also be used in combination with your own attached backup when installing Windows.",
MarkdownDescription: "When this option is enabled a copy of the KVM driver disc for Windows (\"virtio-win.iso\") will be attached to your server as a virtual CD. This option can also be used in combination with your own attached backup when installing Windows.",
},
"emulated_devices": schema.BoolAttribute{
Optional: true,
Computed: true,
Description: "When emulated devices is enabled, the KVM specific \"VirtIO\" disk drive and network devices are removed, and replaced with emulated versions of physical hardware: an old IDE HDD and an Intel E1000 network card. Emulated devices are much slower than the VirtIO devices, and so this option should not be enabled unless absolutely necessary.",
MarkdownDescription: "When emulated devices is enabled, the KVM specific \"VirtIO\" disk drive and network devices are removed, and replaced with emulated versions of physical hardware: an old IDE HDD and an Intel E1000 network card. Emulated devices are much slower than the VirtIO devices, and so this option should not be enabled unless absolutely necessary.",
},
"emulated_hyperv": schema.BoolAttribute{
Optional: true,
Computed: true,
Description: "Enable HyperV (a hypervisor produced by Microsoft) support. Enabled by default on Windows servers, generally of no value for non-Windows servers.",
MarkdownDescription: "Enable HyperV (a hypervisor produced by Microsoft) support. Enabled by default on Windows servers, generally of no value for non-Windows servers.",
},
"emulated_tpm": schema.BoolAttribute{
Optional: true,
Computed: true,
Description: "When enabled this provides an emulated TPM v1.2 device to your Cloud Server. Warning: the TPM state is not backed up.",
MarkdownDescription: "When enabled this provides an emulated TPM v1.2 device to your Cloud Server. Warning: the TPM state is not backed up.",
},
"local_rtc": schema.BoolAttribute{
Optional: true,
Computed: true,
Description: "When a server is booted the virtual BIOS receives the current date and time from the host node. The BIOS does not have an explicit timezone, so the timezone used is implicit and must be understood by the operating system. Most operating systems other than Windows expect the time to be UTC since it allows the operating system to control the timezone used when displaying the time. Our Windows installations have also been customized to use UTC, but when using your own installation of Windows this should be set to the host node's local timezone.",
MarkdownDescription: "When a server is booted the virtual BIOS receives the current date and time from the host node. The BIOS does not have an explicit timezone, so the timezone used is implicit and must be understood by the operating system. Most operating systems other than Windows expect the time to be UTC since it allows the operating system to control the timezone used when displaying the time. Our Windows installations have also been customized to use UTC, but when using your own installation of Windows this should be set to the host node's local timezone.",
},
"nested_virt": schema.BoolAttribute{
Optional: true,
Computed: true,
Description: "When this option is enabled the functionality necessary to run your own KVM servers within your server is enabled. Note that all the networking limits - one MAC address per VPS, restricted to specific IPs - still apply to public cloud so this feature is generally only useful in combination with Virtual Private Cloud.",
MarkdownDescription: "When this option is enabled the functionality necessary to run your own KVM servers within your server is enabled. Note that all the networking limits - one MAC address per VPS, restricted to specific IPs - still apply to public cloud so this feature is generally only useful in combination with Virtual Private Cloud.",
},
"qemu_guest_agent": schema.BoolAttribute{
Computed: true,
Description: "When this option is enabled the server will allow QEMU Guest Agent to perform password reset without rebooting.",
MarkdownDescription: "When this option is enabled the server will allow QEMU Guest Agent to perform password reset without rebooting.",
},
"uefi_boot": schema.BoolAttribute{
Computed: true,
Description: "When this option is enabled the Cloud Server will use UEFI instead of legacy PC BIOS.",
MarkdownDescription: "When this option is enabled the Cloud Server will use UEFI instead of legacy PC BIOS.",
},
"unset_uuid": schema.BoolAttribute{
Optional: true,
Computed: true,
Description: "When this option is NOT enabled a 128-bit unique identifier is exposed to your server through the virtual BIOS. Each server receives a different UUID. Some proprietary licensed software utilize this identifier to \"tie\" the license to a specific server.",
MarkdownDescription: "When this option is NOT enabled a 128-bit unique identifier is exposed to your server through the virtual BIOS. Each server receives a different UUID. Some proprietary licensed software utilize this identifier to \"tie\" the license to a specific server.",
},
},
CustomType: AdvancedFeaturesType{
ObjectType: types.ObjectType{
AttrTypes: AdvancedFeaturesValue{}.AttributeTypes(ctx),
},
},
Optional: true,
Computed: true,
},
"backups": schema.BoolAttribute{
Optional: true,
Computed: true,
@@ -86,14 +160,834 @@ func ServerResourceSchema(ctx context.Context) schema.Schema {
}
type ServerModel struct {
Backups types.Bool `tfsdk:"backups"`
Id types.Int64 `tfsdk:"id"`
Image types.String `tfsdk:"image"`
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"`
AdvancedFeatures AdvancedFeaturesValue `tfsdk:"advanced_features"`
Backups types.Bool `tfsdk:"backups"`
Id types.Int64 `tfsdk:"id"`
Image types.String `tfsdk:"image"`
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"`
}
var _ basetypes.ObjectTypable = AdvancedFeaturesType{}
type AdvancedFeaturesType struct {
basetypes.ObjectType
}
func (t AdvancedFeaturesType) Equal(o attr.Type) bool {
other, ok := o.(AdvancedFeaturesType)
if !ok {
return false
}
return t.ObjectType.Equal(other.ObjectType)
}
func (t AdvancedFeaturesType) String() string {
return "AdvancedFeaturesType"
}
func (t AdvancedFeaturesType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) {
var diags diag.Diagnostics
attributes := in.Attributes()
cloudInitAttribute, ok := attributes["cloud_init"]
if !ok {
diags.AddError(
"Attribute Missing",
`cloud_init is missing from object`)
return nil, diags
}
cloudInitVal, ok := cloudInitAttribute.(basetypes.BoolValue)
if !ok {
diags.AddError(
"Attribute Wrong Type",
fmt.Sprintf(`cloud_init expected to be basetypes.BoolValue, was: %T`, cloudInitAttribute))
}
driverDiskAttribute, ok := attributes["driver_disk"]
if !ok {
diags.AddError(
"Attribute Missing",
`driver_disk is missing from object`)
return nil, diags
}
driverDiskVal, ok := driverDiskAttribute.(basetypes.BoolValue)
if !ok {
diags.AddError(
"Attribute Wrong Type",
fmt.Sprintf(`driver_disk expected to be basetypes.BoolValue, was: %T`, driverDiskAttribute))
}
emulatedDevicesAttribute, ok := attributes["emulated_devices"]
if !ok {
diags.AddError(
"Attribute Missing",
`emulated_devices is missing from object`)
return nil, diags
}
emulatedDevicesVal, ok := emulatedDevicesAttribute.(basetypes.BoolValue)
if !ok {
diags.AddError(
"Attribute Wrong Type",
fmt.Sprintf(`emulated_devices expected to be basetypes.BoolValue, was: %T`, emulatedDevicesAttribute))
}
emulatedHypervAttribute, ok := attributes["emulated_hyperv"]
if !ok {
diags.AddError(
"Attribute Missing",
`emulated_hyperv is missing from object`)
return nil, diags
}
emulatedHypervVal, ok := emulatedHypervAttribute.(basetypes.BoolValue)
if !ok {
diags.AddError(
"Attribute Wrong Type",
fmt.Sprintf(`emulated_hyperv expected to be basetypes.BoolValue, was: %T`, emulatedHypervAttribute))
}
emulatedTpmAttribute, ok := attributes["emulated_tpm"]
if !ok {
diags.AddError(
"Attribute Missing",
`emulated_tpm is missing from object`)
return nil, diags
}
emulatedTpmVal, ok := emulatedTpmAttribute.(basetypes.BoolValue)
if !ok {
diags.AddError(
"Attribute Wrong Type",
fmt.Sprintf(`emulated_tpm expected to be basetypes.BoolValue, was: %T`, emulatedTpmAttribute))
}
localRtcAttribute, ok := attributes["local_rtc"]
if !ok {
diags.AddError(
"Attribute Missing",
`local_rtc is missing from object`)
return nil, diags
}
localRtcVal, ok := localRtcAttribute.(basetypes.BoolValue)
if !ok {
diags.AddError(
"Attribute Wrong Type",
fmt.Sprintf(`local_rtc expected to be basetypes.BoolValue, was: %T`, localRtcAttribute))
}
nestedVirtAttribute, ok := attributes["nested_virt"]
if !ok {
diags.AddError(
"Attribute Missing",
`nested_virt is missing from object`)
return nil, diags
}
nestedVirtVal, ok := nestedVirtAttribute.(basetypes.BoolValue)
if !ok {
diags.AddError(
"Attribute Wrong Type",
fmt.Sprintf(`nested_virt expected to be basetypes.BoolValue, was: %T`, nestedVirtAttribute))
}
qemuGuestAgentAttribute, ok := attributes["qemu_guest_agent"]
if !ok {
diags.AddError(
"Attribute Missing",
`qemu_guest_agent is missing from object`)
return nil, diags
}
qemuGuestAgentVal, ok := qemuGuestAgentAttribute.(basetypes.BoolValue)
if !ok {
diags.AddError(
"Attribute Wrong Type",
fmt.Sprintf(`qemu_guest_agent expected to be basetypes.BoolValue, was: %T`, qemuGuestAgentAttribute))
}
uefiBootAttribute, ok := attributes["uefi_boot"]
if !ok {
diags.AddError(
"Attribute Missing",
`uefi_boot is missing from object`)
return nil, diags
}
uefiBootVal, ok := uefiBootAttribute.(basetypes.BoolValue)
if !ok {
diags.AddError(
"Attribute Wrong Type",
fmt.Sprintf(`uefi_boot expected to be basetypes.BoolValue, was: %T`, uefiBootAttribute))
}
unsetUuidAttribute, ok := attributes["unset_uuid"]
if !ok {
diags.AddError(
"Attribute Missing",
`unset_uuid is missing from object`)
return nil, diags
}
unsetUuidVal, ok := unsetUuidAttribute.(basetypes.BoolValue)
if !ok {
diags.AddError(
"Attribute Wrong Type",
fmt.Sprintf(`unset_uuid expected to be basetypes.BoolValue, was: %T`, unsetUuidAttribute))
}
if diags.HasError() {
return nil, diags
}
return AdvancedFeaturesValue{
CloudInit: cloudInitVal,
DriverDisk: driverDiskVal,
EmulatedDevices: emulatedDevicesVal,
EmulatedHyperv: emulatedHypervVal,
EmulatedTpm: emulatedTpmVal,
LocalRtc: localRtcVal,
NestedVirt: nestedVirtVal,
QemuGuestAgent: qemuGuestAgentVal,
UefiBoot: uefiBootVal,
UnsetUuid: unsetUuidVal,
state: attr.ValueStateKnown,
}, diags
}
func NewAdvancedFeaturesValueNull() AdvancedFeaturesValue {
return AdvancedFeaturesValue{
state: attr.ValueStateNull,
}
}
func NewAdvancedFeaturesValueUnknown() AdvancedFeaturesValue {
return AdvancedFeaturesValue{
state: attr.ValueStateUnknown,
}
}
func NewAdvancedFeaturesValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (AdvancedFeaturesValue, 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 AdvancedFeaturesValue Attribute Value",
"While creating a AdvancedFeaturesValue value, a missing attribute value was detected. "+
"A AdvancedFeaturesValue 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("AdvancedFeaturesValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()),
)
continue
}
if !attributeType.Equal(attribute.Type(ctx)) {
diags.AddError(
"Invalid AdvancedFeaturesValue Attribute Type",
"While creating a AdvancedFeaturesValue value, an invalid attribute value was detected. "+
"A AdvancedFeaturesValue 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("AdvancedFeaturesValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+
fmt.Sprintf("AdvancedFeaturesValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)),
)
}
}
for name := range attributes {
_, ok := attributeTypes[name]
if !ok {
diags.AddError(
"Extra AdvancedFeaturesValue Attribute Value",
"While creating a AdvancedFeaturesValue value, an extra attribute value was detected. "+
"A AdvancedFeaturesValue 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 AdvancedFeaturesValue Attribute Name: %s", name),
)
}
}
if diags.HasError() {
return NewAdvancedFeaturesValueUnknown(), diags
}
cloudInitAttribute, ok := attributes["cloud_init"]
if !ok {
diags.AddError(
"Attribute Missing",
`cloud_init is missing from object`)
return NewAdvancedFeaturesValueUnknown(), diags
}
cloudInitVal, ok := cloudInitAttribute.(basetypes.BoolValue)
if !ok {
diags.AddError(
"Attribute Wrong Type",
fmt.Sprintf(`cloud_init expected to be basetypes.BoolValue, was: %T`, cloudInitAttribute))
}
driverDiskAttribute, ok := attributes["driver_disk"]
if !ok {
diags.AddError(
"Attribute Missing",
`driver_disk is missing from object`)
return NewAdvancedFeaturesValueUnknown(), diags
}
driverDiskVal, ok := driverDiskAttribute.(basetypes.BoolValue)
if !ok {
diags.AddError(
"Attribute Wrong Type",
fmt.Sprintf(`driver_disk expected to be basetypes.BoolValue, was: %T`, driverDiskAttribute))
}
emulatedDevicesAttribute, ok := attributes["emulated_devices"]
if !ok {
diags.AddError(
"Attribute Missing",
`emulated_devices is missing from object`)
return NewAdvancedFeaturesValueUnknown(), diags
}
emulatedDevicesVal, ok := emulatedDevicesAttribute.(basetypes.BoolValue)
if !ok {
diags.AddError(
"Attribute Wrong Type",
fmt.Sprintf(`emulated_devices expected to be basetypes.BoolValue, was: %T`, emulatedDevicesAttribute))
}
emulatedHypervAttribute, ok := attributes["emulated_hyperv"]
if !ok {
diags.AddError(
"Attribute Missing",
`emulated_hyperv is missing from object`)
return NewAdvancedFeaturesValueUnknown(), diags
}
emulatedHypervVal, ok := emulatedHypervAttribute.(basetypes.BoolValue)
if !ok {
diags.AddError(
"Attribute Wrong Type",
fmt.Sprintf(`emulated_hyperv expected to be basetypes.BoolValue, was: %T`, emulatedHypervAttribute))
}
emulatedTpmAttribute, ok := attributes["emulated_tpm"]
if !ok {
diags.AddError(
"Attribute Missing",
`emulated_tpm is missing from object`)
return NewAdvancedFeaturesValueUnknown(), diags
}
emulatedTpmVal, ok := emulatedTpmAttribute.(basetypes.BoolValue)
if !ok {
diags.AddError(
"Attribute Wrong Type",
fmt.Sprintf(`emulated_tpm expected to be basetypes.BoolValue, was: %T`, emulatedTpmAttribute))
}
localRtcAttribute, ok := attributes["local_rtc"]
if !ok {
diags.AddError(
"Attribute Missing",
`local_rtc is missing from object`)
return NewAdvancedFeaturesValueUnknown(), diags
}
localRtcVal, ok := localRtcAttribute.(basetypes.BoolValue)
if !ok {
diags.AddError(
"Attribute Wrong Type",
fmt.Sprintf(`local_rtc expected to be basetypes.BoolValue, was: %T`, localRtcAttribute))
}
nestedVirtAttribute, ok := attributes["nested_virt"]
if !ok {
diags.AddError(
"Attribute Missing",
`nested_virt is missing from object`)
return NewAdvancedFeaturesValueUnknown(), diags
}
nestedVirtVal, ok := nestedVirtAttribute.(basetypes.BoolValue)
if !ok {
diags.AddError(
"Attribute Wrong Type",
fmt.Sprintf(`nested_virt expected to be basetypes.BoolValue, was: %T`, nestedVirtAttribute))
}
qemuGuestAgentAttribute, ok := attributes["qemu_guest_agent"]
if !ok {
diags.AddError(
"Attribute Missing",
`qemu_guest_agent is missing from object`)
return NewAdvancedFeaturesValueUnknown(), diags
}
qemuGuestAgentVal, ok := qemuGuestAgentAttribute.(basetypes.BoolValue)
if !ok {
diags.AddError(
"Attribute Wrong Type",
fmt.Sprintf(`qemu_guest_agent expected to be basetypes.BoolValue, was: %T`, qemuGuestAgentAttribute))
}
uefiBootAttribute, ok := attributes["uefi_boot"]
if !ok {
diags.AddError(
"Attribute Missing",
`uefi_boot is missing from object`)
return NewAdvancedFeaturesValueUnknown(), diags
}
uefiBootVal, ok := uefiBootAttribute.(basetypes.BoolValue)
if !ok {
diags.AddError(
"Attribute Wrong Type",
fmt.Sprintf(`uefi_boot expected to be basetypes.BoolValue, was: %T`, uefiBootAttribute))
}
unsetUuidAttribute, ok := attributes["unset_uuid"]
if !ok {
diags.AddError(
"Attribute Missing",
`unset_uuid is missing from object`)
return NewAdvancedFeaturesValueUnknown(), diags
}
unsetUuidVal, ok := unsetUuidAttribute.(basetypes.BoolValue)
if !ok {
diags.AddError(
"Attribute Wrong Type",
fmt.Sprintf(`unset_uuid expected to be basetypes.BoolValue, was: %T`, unsetUuidAttribute))
}
if diags.HasError() {
return NewAdvancedFeaturesValueUnknown(), diags
}
return AdvancedFeaturesValue{
CloudInit: cloudInitVal,
DriverDisk: driverDiskVal,
EmulatedDevices: emulatedDevicesVal,
EmulatedHyperv: emulatedHypervVal,
EmulatedTpm: emulatedTpmVal,
LocalRtc: localRtcVal,
NestedVirt: nestedVirtVal,
QemuGuestAgent: qemuGuestAgentVal,
UefiBoot: uefiBootVal,
UnsetUuid: unsetUuidVal,
state: attr.ValueStateKnown,
}, diags
}
func NewAdvancedFeaturesValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) AdvancedFeaturesValue {
object, diags := NewAdvancedFeaturesValue(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("NewAdvancedFeaturesValueMust received error(s): " + strings.Join(diagsStrings, "\n"))
}
return object
}
func (t AdvancedFeaturesType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) {
if in.Type() == nil {
return NewAdvancedFeaturesValueNull(), 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 NewAdvancedFeaturesValueUnknown(), nil
}
if in.IsNull() {
return NewAdvancedFeaturesValueNull(), 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 NewAdvancedFeaturesValueMust(AdvancedFeaturesValue{}.AttributeTypes(ctx), attributes), nil
}
func (t AdvancedFeaturesType) ValueType(ctx context.Context) attr.Value {
return AdvancedFeaturesValue{}
}
var _ basetypes.ObjectValuable = AdvancedFeaturesValue{}
type AdvancedFeaturesValue struct {
CloudInit basetypes.BoolValue `tfsdk:"cloud_init"`
DriverDisk basetypes.BoolValue `tfsdk:"driver_disk"`
EmulatedDevices basetypes.BoolValue `tfsdk:"emulated_devices"`
EmulatedHyperv basetypes.BoolValue `tfsdk:"emulated_hyperv"`
EmulatedTpm basetypes.BoolValue `tfsdk:"emulated_tpm"`
LocalRtc basetypes.BoolValue `tfsdk:"local_rtc"`
NestedVirt basetypes.BoolValue `tfsdk:"nested_virt"`
QemuGuestAgent basetypes.BoolValue `tfsdk:"qemu_guest_agent"`
UefiBoot basetypes.BoolValue `tfsdk:"uefi_boot"`
UnsetUuid basetypes.BoolValue `tfsdk:"unset_uuid"`
state attr.ValueState
}
func (v AdvancedFeaturesValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) {
attrTypes := make(map[string]tftypes.Type, 10)
var val tftypes.Value
var err error
attrTypes["cloud_init"] = basetypes.BoolType{}.TerraformType(ctx)
attrTypes["driver_disk"] = basetypes.BoolType{}.TerraformType(ctx)
attrTypes["emulated_devices"] = basetypes.BoolType{}.TerraformType(ctx)
attrTypes["emulated_hyperv"] = basetypes.BoolType{}.TerraformType(ctx)
attrTypes["emulated_tpm"] = basetypes.BoolType{}.TerraformType(ctx)
attrTypes["local_rtc"] = basetypes.BoolType{}.TerraformType(ctx)
attrTypes["nested_virt"] = basetypes.BoolType{}.TerraformType(ctx)
attrTypes["qemu_guest_agent"] = basetypes.BoolType{}.TerraformType(ctx)
attrTypes["uefi_boot"] = basetypes.BoolType{}.TerraformType(ctx)
attrTypes["unset_uuid"] = basetypes.BoolType{}.TerraformType(ctx)
objectType := tftypes.Object{AttributeTypes: attrTypes}
switch v.state {
case attr.ValueStateKnown:
vals := make(map[string]tftypes.Value, 10)
val, err = v.CloudInit.ToTerraformValue(ctx)
if err != nil {
return tftypes.NewValue(objectType, tftypes.UnknownValue), err
}
vals["cloud_init"] = val
val, err = v.DriverDisk.ToTerraformValue(ctx)
if err != nil {
return tftypes.NewValue(objectType, tftypes.UnknownValue), err
}
vals["driver_disk"] = val
val, err = v.EmulatedDevices.ToTerraformValue(ctx)
if err != nil {
return tftypes.NewValue(objectType, tftypes.UnknownValue), err
}
vals["emulated_devices"] = val
val, err = v.EmulatedHyperv.ToTerraformValue(ctx)
if err != nil {
return tftypes.NewValue(objectType, tftypes.UnknownValue), err
}
vals["emulated_hyperv"] = val
val, err = v.EmulatedTpm.ToTerraformValue(ctx)
if err != nil {
return tftypes.NewValue(objectType, tftypes.UnknownValue), err
}
vals["emulated_tpm"] = val
val, err = v.LocalRtc.ToTerraformValue(ctx)
if err != nil {
return tftypes.NewValue(objectType, tftypes.UnknownValue), err
}
vals["local_rtc"] = val
val, err = v.NestedVirt.ToTerraformValue(ctx)
if err != nil {
return tftypes.NewValue(objectType, tftypes.UnknownValue), err
}
vals["nested_virt"] = val
val, err = v.QemuGuestAgent.ToTerraformValue(ctx)
if err != nil {
return tftypes.NewValue(objectType, tftypes.UnknownValue), err
}
vals["qemu_guest_agent"] = val
val, err = v.UefiBoot.ToTerraformValue(ctx)
if err != nil {
return tftypes.NewValue(objectType, tftypes.UnknownValue), err
}
vals["uefi_boot"] = val
val, err = v.UnsetUuid.ToTerraformValue(ctx)
if err != nil {
return tftypes.NewValue(objectType, tftypes.UnknownValue), err
}
vals["unset_uuid"] = 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 AdvancedFeaturesValue) IsNull() bool {
return v.state == attr.ValueStateNull
}
func (v AdvancedFeaturesValue) IsUnknown() bool {
return v.state == attr.ValueStateUnknown
}
func (v AdvancedFeaturesValue) String() string {
return "AdvancedFeaturesValue"
}
func (v AdvancedFeaturesValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) {
var diags diag.Diagnostics
attributeTypes := map[string]attr.Type{
"cloud_init": basetypes.BoolType{},
"driver_disk": basetypes.BoolType{},
"emulated_devices": basetypes.BoolType{},
"emulated_hyperv": basetypes.BoolType{},
"emulated_tpm": basetypes.BoolType{},
"local_rtc": basetypes.BoolType{},
"nested_virt": basetypes.BoolType{},
"qemu_guest_agent": basetypes.BoolType{},
"uefi_boot": basetypes.BoolType{},
"unset_uuid": basetypes.BoolType{},
}
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{
"cloud_init": v.CloudInit,
"driver_disk": v.DriverDisk,
"emulated_devices": v.EmulatedDevices,
"emulated_hyperv": v.EmulatedHyperv,
"emulated_tpm": v.EmulatedTpm,
"local_rtc": v.LocalRtc,
"nested_virt": v.NestedVirt,
"qemu_guest_agent": v.QemuGuestAgent,
"uefi_boot": v.UefiBoot,
"unset_uuid": v.UnsetUuid,
})
return objVal, diags
}
func (v AdvancedFeaturesValue) Equal(o attr.Value) bool {
other, ok := o.(AdvancedFeaturesValue)
if !ok {
return false
}
if v.state != other.state {
return false
}
if v.state != attr.ValueStateKnown {
return true
}
if !v.CloudInit.Equal(other.CloudInit) {
return false
}
if !v.DriverDisk.Equal(other.DriverDisk) {
return false
}
if !v.EmulatedDevices.Equal(other.EmulatedDevices) {
return false
}
if !v.EmulatedHyperv.Equal(other.EmulatedHyperv) {
return false
}
if !v.EmulatedTpm.Equal(other.EmulatedTpm) {
return false
}
if !v.LocalRtc.Equal(other.LocalRtc) {
return false
}
if !v.NestedVirt.Equal(other.NestedVirt) {
return false
}
if !v.QemuGuestAgent.Equal(other.QemuGuestAgent) {
return false
}
if !v.UefiBoot.Equal(other.UefiBoot) {
return false
}
if !v.UnsetUuid.Equal(other.UnsetUuid) {
return false
}
return true
}
func (v AdvancedFeaturesValue) Type(ctx context.Context) attr.Type {
return AdvancedFeaturesType{
basetypes.ObjectType{
AttrTypes: v.AttributeTypes(ctx),
},
}
}
func (v AdvancedFeaturesValue) AttributeTypes(ctx context.Context) map[string]attr.Type {
return map[string]attr.Type{
"cloud_init": basetypes.BoolType{},
"driver_disk": basetypes.BoolType{},
"emulated_devices": basetypes.BoolType{},
"emulated_hyperv": basetypes.BoolType{},
"emulated_tpm": basetypes.BoolType{},
"local_rtc": basetypes.BoolType{},
"nested_virt": basetypes.BoolType{},
"qemu_guest_agent": basetypes.BoolType{},
"uefi_boot": basetypes.BoolType{},
"unset_uuid": basetypes.BoolType{},
}
}
@@ -6266,18 +6266,6 @@
"description": "Create an Additional Disk for a Server"
},
"AdvancedFeature": {
"enum": [
"emulated-hyperv",
"emulated-devices",
"nested-virt",
"driver-disk",
"unset-uuid",
"local-rtc",
"emulated-tpm",
"cloud-init",
"qemu-guest-agent",
"uefi-boot"
],
"type": "string",
"description": "\n| Value | Description |\n| ----- | ----------- |\n| emulated-hyperv | Enable HyperV (a hypervisor produced by Microsoft) support. Enabled by default on Windows servers, generally of no value for non-Windows servers. |\n| emulated-devices | When emulated devices is enabled, the KVM specific \"VirtIO\" disk drive and network devices are removed, and replaced with emulated versions of physical hardware: an old IDE HDD and an Intel E1000 network card. Emulated devices are much slower than the VirtIO devices, and so this option should not be enabled unless absolutely necessary. |\n| nested-virt | When this option is enabled the functionality necessary to run your own KVM servers within your server is enabled. Note that all the networking limits - one MAC address per VPS, restricted to specific IPs - still apply to public cloud so this is feature is generally only useful in combination with Virtual Private Cloud. |\n| driver-disk | When this option is enabled a copy of the KVM driver disc for Windows (\"virtio-win.iso\") will be attached to your server as a virtual CD. This option can also be used in combination with your own attached backup when installing Windows. |\n| unset-uuid | When this option is NOT enabled a 128-bit unique identifier is exposed to your server through the virtual BIOS. Each server receives a different UUID. Some propriety licensed software utilise this identifier to \"tie\" the license to a specific server. |\n| local-rtc | When a server is booted the virtual BIOS receives the current date and time from the host node. The BIOS does not have an explicit timezone, so the timezone used is implicit and must be understood by the operating system. Most operating systems other than Windows expect the time to be UTC since it allows the operating system to control the timezone used when displaying the time. Our Windows installations have also been customized to use UTC, but when using your own installation of Windows this should be set to the host node's local timezone. |\n| emulated-tpm | When enabled this provides an emulated TPM v1.2 device to your Cloud Server. Warning: the TPM state is not backed up. |\n| cloud-init | (Read-Only) When this option is enabled the Cloud Server will be provided a datasource for the cloud-init service. |\n| qemu-guest-agent | (Read-Only) When this option is enabled the server will allow QEMU Guest Agent to perform password reset without rebooting. |\n| uefi-boot | (Read-Only) When this option is enabled the Cloud Server will use UEFI instead of legacy PC BIOS. |\n\n",
"x-enum-descriptions": [
@@ -6454,7 +6442,7 @@
"enabled_advanced_features": {
"type": "array",
"items": {
"$ref": "#/components/schemas/AdvancedFeature"
"type": "string"
},
"description": "A list of the currently enabled advanced features for this server.",
"readOnly": true
@@ -6547,7 +6535,7 @@
"advanced_features": {
"type": "array",
"items": {
"$ref": "#/components/schemas/AdvancedFeature"
"type": "string"
},
"description": "A list of the advanced features available for this server.",
"readOnly": true
@@ -6846,7 +6834,7 @@
"enabled_advanced_features": {
"type": "array",
"items": {
"$ref": "#/components/schemas/AdvancedFeature"
"type": "string"
},
"description": "Do not provide or set to null to keep existing advanced features. Provide an empty array to disable all advanced features, otherwise provide an array with selected advanced features. If provided, any currently enabled advanced features that aren't included will be disabled.",
"nullable": true
@@ -12336,18 +12324,20 @@
"pc_i440fx_4point2",
"pc_i440fx_5point0",
"pc_i440fx_5point1",
"pc_i440fx_7point2"
"pc_i440fx_7point2",
"pc_i440fx_8point2"
],
"type": "string",
"description": "\n| Value | Description |\n| ----- | ----------- |\n| pc_i440fx_1point5 | PC I440 FX 1.5 |\n| pc_i440fx_2point11 | PC I440 FX 2.11 |\n| pc_i440fx_4point1 | PC I440 FX 4.1 |\n| pc_i440fx_4point2 | PC I440 FX 4.2 |\n| pc_i440fx_5point0 | PC I440 FX 5.0 |\n| pc_i440fx_5point1 | PC I440 FX 5.1 |\n| pc_i440fx_7point2 | PC I440 FX 7.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_8point2 | PC i440FX 8.2 |\n\n",
"x-enum-descriptions": [
"PC I440 FX 1.5",
"PC I440 FX 2.11",
"PC I440 FX 4.1",
"PC I440 FX 4.2",
"PC I440 FX 5.0",
"PC I440 FX 5.1",
"PC I440 FX 7.2"
"PC i440FX 1.5",
"PC i440FX 2.11",
"PC i440FX 4.1",
"PC i440FX 4.2",
"PC i440FX 5.0",
"PC i440FX 5.1",
"PC i440FX 7.2",
"PC i440FX 8.2"
]
},
"Vpc": {
+80 -2
View File
@@ -753,7 +753,7 @@
"path": "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
}
],
"schema_definition": "stringvalidator.RegexMatches(regexp.MustCompile(\"/[A-Za-z0-9/.?=\u0026+%_-]*\"), \"\")"
"schema_definition": "stringvalidator.RegexMatches(regexp.MustCompile(\"/[A-Za-z0-9/.?=&+%_-]*\"), \"\")"
}
}
]
@@ -928,6 +928,84 @@
"computed_optional_required": "computed_optional",
"description": "The ID of the server to fetch."
}
},
{
"name": "advanced_features",
"single_nested": {
"computed_optional_required": "computed_optional",
"attributes": [
{
"name": "emulated_hyperv",
"bool": {
"computed_optional_required": "computed_optional",
"description": "Enable HyperV (a hypervisor produced by Microsoft) support. Enabled by default on Windows servers, generally of no value for non-Windows servers."
}
},
{
"name": "emulated_devices",
"bool": {
"computed_optional_required": "computed_optional",
"description": "When emulated devices is enabled, the KVM specific \"VirtIO\" disk drive and network devices are removed, and replaced with emulated versions of physical hardware: an old IDE HDD and an Intel E1000 network card. Emulated devices are much slower than the VirtIO devices, and so this option should not be enabled unless absolutely necessary."
}
},
{
"name": "nested_virt",
"bool": {
"computed_optional_required": "computed_optional",
"description": "When this option is enabled the functionality necessary to run your own KVM servers within your server is enabled. Note that all the networking limits - one MAC address per VPS, restricted to specific IPs - still apply to public cloud so this feature is generally only useful in combination with Virtual Private Cloud."
}
},
{
"name": "driver_disk",
"bool": {
"computed_optional_required": "computed_optional",
"description": "When this option is enabled a copy of the KVM driver disc for Windows (\"virtio-win.iso\") will be attached to your server as a virtual CD. This option can also be used in combination with your own attached backup when installing Windows."
}
},
{
"name": "unset_uuid",
"bool": {
"computed_optional_required": "computed_optional",
"description": "When this option is NOT enabled a 128-bit unique identifier is exposed to your server through the virtual BIOS. Each server receives a different UUID. Some proprietary licensed software utilize this identifier to \"tie\" the license to a specific server."
}
},
{
"name": "local_rtc",
"bool": {
"computed_optional_required": "computed_optional",
"description": "When a server is booted the virtual BIOS receives the current date and time from the host node. The BIOS does not have an explicit timezone, so the timezone used is implicit and must be understood by the operating system. Most operating systems other than Windows expect the time to be UTC since it allows the operating system to control the timezone used when displaying the time. Our Windows installations have also been customized to use UTC, but when using your own installation of Windows this should be set to the host node's local timezone."
}
},
{
"name": "emulated_tpm",
"bool": {
"computed_optional_required": "computed_optional",
"description": "When enabled this provides an emulated TPM v1.2 device to your Cloud Server. Warning: the TPM state is not backed up."
}
},
{
"name": "cloud_init",
"bool": {
"computed_optional_required": "computed",
"description": "When this option is enabled the Cloud Server will be provided a datasource for the cloud-init service."
}
},
{
"name": "qemu_guest_agent",
"bool": {
"computed_optional_required": "computed",
"description": "When this option is enabled the server will allow QEMU Guest Agent to perform password reset without rebooting."
}
},
{
"name": "uefi_boot",
"bool": {
"computed_optional_required": "computed",
"description": "When this option is enabled the Cloud Server will use UEFI instead of legacy PC BIOS."
}
}
]
}
}
]
}
@@ -1251,4 +1329,4 @@
}
],
"version": "0.1"
}
}
+78
View File
@@ -0,0 +1,78 @@
{
"name": "advanced_features",
"single_nested": {
"computed_optional_required": "computed_optional",
"attributes": [
{
"name": "emulated_hyperv",
"bool": {
"computed_optional_required": "computed_optional",
"description": "Enable HyperV (a hypervisor produced by Microsoft) support. Enabled by default on Windows servers, generally of no value for non-Windows servers."
}
},
{
"name": "emulated_devices",
"bool": {
"computed_optional_required": "computed_optional",
"description": "When emulated devices is enabled, the KVM specific \"VirtIO\" disk drive and network devices are removed, and replaced with emulated versions of physical hardware: an old IDE HDD and an Intel E1000 network card. Emulated devices are much slower than the VirtIO devices, and so this option should not be enabled unless absolutely necessary."
}
},
{
"name": "nested_virt",
"bool": {
"computed_optional_required": "computed_optional",
"description": "When this option is enabled the functionality necessary to run your own KVM servers within your server is enabled. Note that all the networking limits - one MAC address per VPS, restricted to specific IPs - still apply to public cloud so this feature is generally only useful in combination with Virtual Private Cloud."
}
},
{
"name": "driver_disk",
"bool": {
"computed_optional_required": "computed_optional",
"description": "When this option is enabled a copy of the KVM driver disc for Windows (\"virtio-win.iso\") will be attached to your server as a virtual CD. This option can also be used in combination with your own attached backup when installing Windows."
}
},
{
"name": "unset_uuid",
"bool": {
"computed_optional_required": "computed_optional",
"description": "When this option is NOT enabled a 128-bit unique identifier is exposed to your server through the virtual BIOS. Each server receives a different UUID. Some proprietary licensed software utilize this identifier to \"tie\" the license to a specific server."
}
},
{
"name": "local_rtc",
"bool": {
"computed_optional_required": "computed_optional",
"description": "When a server is booted the virtual BIOS receives the current date and time from the host node. The BIOS does not have an explicit timezone, so the timezone used is implicit and must be understood by the operating system. Most operating systems other than Windows expect the time to be UTC since it allows the operating system to control the timezone used when displaying the time. Our Windows installations have also been customized to use UTC, but when using your own installation of Windows this should be set to the host node's local timezone."
}
},
{
"name": "emulated_tpm",
"bool": {
"computed_optional_required": "computed_optional",
"description": "When enabled this provides an emulated TPM v1.2 device to your Cloud Server. Warning: the TPM state is not backed up."
}
},
{
"name": "cloud_init",
"bool": {
"computed_optional_required": "computed",
"description": "When this option is enabled the Cloud Server will be provided a datasource for the cloud-init service."
}
},
{
"name": "qemu_guest_agent",
"bool": {
"computed_optional_required": "computed",
"description": "When this option is enabled the server will allow QEMU Guest Agent to perform password reset without rebooting."
}
},
{
"name": "uefi_boot",
"bool": {
"computed_optional_required": "computed",
"description": "When this option is enabled the Cloud Server will use UEFI instead of legacy PC BIOS."
}
}
]
}
}
+7
View File
@@ -0,0 +1,7 @@
#!/bin/bash
GENERATOR_CONFIG=$(dirname "$0")/../provider_code_spec.json
# Advanced features configuration
ADVANCED_FEATURES_CONFIG=$(dirname "$0")/data/advanced_features.json
cat <<<$(jq --tab --slurpfile adv_feat_cfg $ADVANCED_FEATURES_CONFIG '.resources[1].schema.attributes |= . + $adv_feat_cfg' $GENERATOR_CONFIG) >$GENERATOR_CONFIG
@@ -1,6 +1,6 @@
#!/bin/bash
OPENAPI_FILE=$(dirname "$0")/openapi.json
OPENAPI_FILE=$(dirname "$0")/../openapi.json
# Fetch the latest OpenAPI spec
curl https://api.binarylane.com.au/reference/openapi.json --output $OPENAPI_FILE
@@ -27,6 +27,10 @@ cat <<<$(jq '.paths["/account/keys/{key_id}"].delete.parameters[0].schema |= del
cat <<<$(jq '.paths["/account/keys/{key_id}"].delete.parameters[0].schema |= del(.oneOf) + {type:"integer"}' $OPENAPI_FILE) >$OPENAPI_FILE
cat <<<$(jq '.paths["/images"].get.parameters[0].schema |= del(.allOf) + {type:"string"}' $OPENAPI_FILE) >$OPENAPI_FILE
cat <<<$(jq '.paths["/sizes"].get.parameters[1].schema |= del(.oneOf) + {type:"string"}' $OPENAPI_FILE) >$OPENAPI_FILE
cat <<<$(jq '.components.schemas.AdvancedFeature |= del(.enum)' $OPENAPI_FILE) >$OPENAPI_FILE
cat <<<$(jq '.components.schemas.AdvancedServerFeatures.properties.enabled_advanced_features.items |= del(.["$ref"]) + {type:"string"}' $OPENAPI_FILE) >$OPENAPI_FILE
cat <<<$(jq '.components.schemas.ChangeAdvancedFeatures.properties.enabled_advanced_features.items |= del(.["$ref"]) + {type:"string"}' $OPENAPI_FILE) >$OPENAPI_FILE
cat <<<$(jq '.components.schemas.AvailableAdvancedServerFeatures.properties.advanced_features.items |= del(.["$ref"]) + {type:"string"}' $OPENAPI_FILE) >$OPENAPI_FILE
# Remove the "/paths/{image_id}" path because its duplicated by "/images/{image_id_or_slug}"
cat <<<$(jq 'del(.paths."/images/{image_id}")' $OPENAPI_FILE) >$OPENAPI_FILE