mirror of
https://github.com/oscarhermoso/terraform-provider-binarylane
synced 2026-10-19 21:49:15 +11:00
Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a0a227c88c | |||
| f8edcd0e06 | |||
| 04552e0fcf | |||
| 66fcb6f85e | |||
| 806bdebaf8 | |||
| dd06380c63 | |||
| 322a8fda80 | |||
| a50daac8e9 | |||
| 424828123d | |||
| 4c50298eca | |||
| cbef2be0fe | |||
| 5767bb6739 | |||
| 74eac97fe8 | |||
| a30b6b14a7 | |||
| 0a4156269f | |||
| 0adff101c6 | |||
| 5e3b30a49b | |||
| 45d7ab450c | |||
| c5b250becf | |||
| 10070095e1 | |||
| 24f05a6266 | |||
| 86b980c91b | |||
| 21b43d92b9 | |||
| e70e10c4c9 | |||
| 75a387e19d | |||
| 11e0302e71 | |||
| 4677e34166 | |||
| 3f518b2ca3 | |||
| 90b94254f1 | |||
| 46117cf31d | |||
| 394638ff57 | |||
| 239e48e940 | |||
| 2221f8c853 | |||
| 95487045c4 | |||
| 7f5bae6b15 | |||
| 4ef9df6edf | |||
| 547763d639 | |||
| f5fecdd69c | |||
| cd85f67e28 | |||
| 50d06b967b |
@@ -23,7 +23,7 @@ jobs:
|
||||
needs: test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
# Allow goreleaser to access older tag information.
|
||||
fetch-depth: 0
|
||||
@@ -32,16 +32,21 @@ jobs:
|
||||
go-version-file: 'go.mod'
|
||||
cache: true
|
||||
- name: Import GPG key
|
||||
uses: crazy-max/ghaction-import-gpg@cb9bde2e2525e640591a934b1fd28eef1dcaf5e5 # v6.2.0
|
||||
uses: crazy-max/ghaction-import-gpg@e89d40939c28e39f97cf32126055eeae86ba74ec # v6.3.0
|
||||
id: import_gpg
|
||||
with:
|
||||
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@e435ccd777264be153ace6237001ef4d979d3a7a # v6.4.0
|
||||
with:
|
||||
args: release --clean
|
||||
env:
|
||||
# GitHub sets the GITHUB_TOKEN secret automatically.
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }}
|
||||
- name: Publish Release
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
run: gh release edit "${{ github.ref }}" --draft false
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
group: test
|
||||
cancel-in-progress: true # would be nice if GH offered cancel-pending instead, https://github.com/orgs/community/discussions/63136
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: 'go.mod'
|
||||
@@ -54,7 +54,7 @@ jobs:
|
||||
# name: Unit Tests
|
||||
# runs-on: ubuntu-latest
|
||||
# steps:
|
||||
# - uses: actions/checkout@v4
|
||||
# - uses: actions/checkout@v5
|
||||
# - uses: actions/setup-go@v5
|
||||
# with:
|
||||
# go-version-file: 'go.mod'
|
||||
|
||||
Vendored
+3
@@ -1,3 +1,6 @@
|
||||
{
|
||||
"go.testEnvFile": "${workspaceFolder}/.env",
|
||||
"go.testEnvVars": {
|
||||
"TF_LOG": "TRACE"
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -67,7 +67,7 @@ go generate
|
||||
```sh
|
||||
tfplugingen-framework scaffold resource \
|
||||
--output-dir ./internal/provider \
|
||||
--name REPLACE_ME
|
||||
--name REPLACE_ME # eg. server
|
||||
```
|
||||
|
||||
```sh
|
||||
@@ -163,8 +163,8 @@ Define the interfaces that the data source should implement:
|
||||
Add the API client to the data source:
|
||||
|
||||
```diff
|
||||
- type exampleResource struct{}
|
||||
+ type exampleResource struct {
|
||||
- type exampleDataSource struct{}
|
||||
+ type exampleDataSource struct {
|
||||
+ bc *BinarylaneClient
|
||||
+ }
|
||||
```
|
||||
|
||||
@@ -18,10 +18,11 @@ Planned features:
|
||||
- [x] Servers
|
||||
- [x] Firewall Rules
|
||||
- [x] Cloud Init
|
||||
- [ ] Updating server properties
|
||||
- [ ] Backups
|
||||
- [x] Updating server properties
|
||||
- [x] "Advanced Features"
|
||||
- [x] IPV6
|
||||
- [ ] Customised Backups
|
||||
- [ ] Software
|
||||
- [ ] IPV6
|
||||
- [ ] Alerts
|
||||
- [x] SSH Keys
|
||||
- [x] Virtual Private Cloud
|
||||
@@ -35,13 +36,39 @@ Planned features:
|
||||
- [x] Examples
|
||||
- [x] Basic
|
||||
- [x] Cloud Init
|
||||
- [x] K3s
|
||||
- [ ] NixOS
|
||||
- [ ] Virtual Private Cloud
|
||||
- [ ] Kubernetes
|
||||
|
||||
## Parameters
|
||||
## Server parameters
|
||||
|
||||
Images:
|
||||
### Regions
|
||||
|
||||
<details>
|
||||
<summary>curl for regions</summary>
|
||||
|
||||
```sh
|
||||
curl -X GET "https://api.binarylane.com.au/v2/regions" \
|
||||
-H "Authorization: Bearer $BINARYLANE_API_TOKEN" > tmp/regions.json
|
||||
|
||||
jq '[ .regions[] | .slug ] | sort' tmp/regions.json
|
||||
```
|
||||
</details>
|
||||
|
||||
```json
|
||||
[
|
||||
"bne",
|
||||
"mel",
|
||||
"per",
|
||||
"sin",
|
||||
"syd"
|
||||
]
|
||||
```
|
||||
|
||||
### Images
|
||||
|
||||
<details>
|
||||
<summary>curl for images</summary>
|
||||
|
||||
```sh
|
||||
curl -X GET "https://api.binarylane.com.au/v2/images?type=distribution&&page=1&per_page=200" \
|
||||
@@ -49,6 +76,7 @@ curl -X GET "https://api.binarylane.com.au/v2/images?type=distribution&&page=1&p
|
||||
|
||||
jq '[ .images[] | .slug ] | sort' tmp/images.json
|
||||
```
|
||||
</details>
|
||||
|
||||
```json
|
||||
[
|
||||
@@ -78,29 +106,10 @@ jq '[ .images[] | .slug ] | sort' tmp/images.json
|
||||
]
|
||||
```
|
||||
|
||||
Regions:
|
||||
|
||||
```sh
|
||||
curl -X GET "https://api.binarylane.com.au/v2/regions" \
|
||||
-H "Authorization: Bearer $BINARYLANE_API_TOKEN" > tmp/regions.json
|
||||
|
||||
jq '[ .regions[] | .slug ] | sort' tmp/regions.json
|
||||
```
|
||||
|
||||
```json
|
||||
[
|
||||
"bne",
|
||||
"mel",
|
||||
"per",
|
||||
"sin",
|
||||
"syd"
|
||||
]
|
||||
```
|
||||
|
||||
### Sizes
|
||||
|
||||
<details>
|
||||
<summary>VM size</summary>
|
||||
<summary>curl for sizes</summary>
|
||||
|
||||
```sh
|
||||
curl -X GET "https://api.binarylane.com.au/v2/sizes" \
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
---
|
||||
# generated by https://github.com/hashicorp/terraform-plugin-docs
|
||||
page_title: "binarylane_images Data Source - terraform-provider-binarylane"
|
||||
subcategory: ""
|
||||
description: |-
|
||||
|
||||
---
|
||||
|
||||
# binarylane_images (Data Source)
|
||||
|
||||
|
||||
|
||||
## Example Usage
|
||||
|
||||
```terraform
|
||||
data "binarylane_images" "example" {
|
||||
}
|
||||
```
|
||||
|
||||
<!-- schema generated by tfplugindocs -->
|
||||
## Schema
|
||||
|
||||
### Optional
|
||||
|
||||
- `type` (String) Queries for distribution will include images that have pre-installed applications.
|
||||
|
||||
### Read-Only
|
||||
|
||||
- `images` (Attributes List) (see [below for nested schema](#nestedatt--images))
|
||||
|
||||
<a id="nestedatt--images"></a>
|
||||
### Nested Schema for `images`
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `backup_info` (Attributes) If this image is a backup, this object will provide further information. (see [below for nested schema](#nestedatt--images--backup_info))
|
||||
- `created_at` (String) If this is a backup image this is the date and time in ISO8601 format when the image was created.
|
||||
- `description` (String) A description that may provide further details or warnings about the image.
|
||||
- `distribution` (String) If this is an operating system image, this is the name of the distribution. If this is a backup image, this is the name of the distribution the server is using.
|
||||
- `distribution_info` (Attributes) This object may provide further information about the distribution. (see [below for nested schema](#nestedatt--images--distribution_info))
|
||||
- `distribution_surcharges` (Attributes) If this is not null the use of this image may incur surcharges above the base cost of the server. All costs are in AU$. (see [below for nested schema](#nestedatt--images--distribution_surcharges))
|
||||
- `error_message` (String) If the image creation failed this may provide further information.
|
||||
- `full_name` (String) If this is an operating system image, this is the name and version of the distribution. If this is a backup image, this is the server hostname and label of the backup if it exists, otherwise it is the server hostname and UTC timestamp of the creation of the image.
|
||||
- `id` (Number) The ID of this image.
|
||||
- `min_disk_size` (Number) For a distribution image this is the minimum disk size in GB required to install the operating system. For a backup image this is the minimum total disk size in GB required to restore the backup.
|
||||
- `min_memory_megabytes` (Number) This is minimum memory in MB necessary to support this operating system (or the base operating system for a backup image).
|
||||
- `name` (String) If this is an operating system image, this is the name of the operating system version. If this is a backup image, this is the label of the backup if it exists, otherwise it is the UTC timestamp of the creation of the image.
|
||||
- `public` (Boolean) A public image is available to all users. A private image is available only to the account that created the image.
|
||||
- `regions` (List of String) The slugs of the regions where the image is available for use.
|
||||
- `size_gigabytes` (Number) For a distribution image this is the disk size used in GB by the operating system on initial install. For a backup image this is the size of the compressed backup image in GB.
|
||||
- `slug` (String) If this is an operating system image this is a slug which may be used as an alternative to the ID as a reference.
|
||||
- `status` (String) | Value | Description |
|
||||
| ----- | ----------- |
|
||||
| NEW | The image is new. |
|
||||
| available | The image is available for use. |
|
||||
| pending | The image is pending and is not yet available for use. |
|
||||
| deleted | The image has been deleted and is no longer available for use. |
|
||||
- `type` (String) | Value | Description |
|
||||
| ----- | ----------- |
|
||||
| custom | An image uploaded by a user. |
|
||||
| snapshot | A snapshot. Snapshot creation is not currently supported so only distribution images will have this value. |
|
||||
| backup | A backup of a server. |
|
||||
|
||||
<a id="nestedatt--images--backup_info"></a>
|
||||
### Nested Schema for `images.backup_info`
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `backup_disks` (Attributes List) A list of the individual disks that make up this backup. (see [below for nested schema](#nestedatt--images--backup_info--backup_disks))
|
||||
- `iso` (Boolean) If this is true the backup is an ISO image and cannot be restored or downloaded. ISO images may only be attached for use as a boot disk or an additional disk.
|
||||
- `locked` (Boolean) If this is true the backup is locked and cannot be replaced.
|
||||
- `offsite` (Boolean) If this is true, an attempt to create an offsite copy was made. This does not mean that the offsite copy attempt was successful or that the copy still exists.
|
||||
- `server_id` (Number) The server ID that was used to create this backup.
|
||||
- `type` (String) | Value | Description |
|
||||
| ----- | ----------- |
|
||||
| daily | A backup which is scheduled to be taken each day. |
|
||||
| weekly | A backup which is scheduled to be taken each week. |
|
||||
| monthly | A backup which is scheduled to be taken each month. |
|
||||
| temporary | A backup which is created on demand and only retained for a maximum of seven days. |
|
||||
|
||||
<a id="nestedatt--images--backup_info--backup_disks"></a>
|
||||
### Nested Schema for `images.backup_info.backup_disks`
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `description` (String) A description of this disk.
|
||||
- `id` (Number) The ID of this backup disk.
|
||||
- `min_disk_size` (Number) This is the minimum disk size in GB required to restore this disk image.
|
||||
- `size_gigabytes` (Number) This is the compressed size of the disk image in GB.
|
||||
|
||||
|
||||
|
||||
<a id="nestedatt--images--distribution_info"></a>
|
||||
### Nested Schema for `images.distribution_info`
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `features` (List of String) Features supported by this distribution.
|
||||
- `image_id` (Number) If this is a backup image, the operating system ID of the server at the time the backup was created.
|
||||
- `password_recovery` (String) Supported methods of password recovery.
|
||||
|
||||
| Value | Description |
|
||||
| ----- | ----------- |
|
||||
| manual | Password must be reset manually using the recovery console and rescue disk. |
|
||||
| offline-clear | Password can be cleared for the admin/root user only. New password needs to be provided on login via the console (Requires restart). |
|
||||
| offline-change | Password can be reset and new credentials sent (Requires restart). |
|
||||
| online-change | Password may be reset without requiring a reboot via installed QEMU Guest Agent. |
|
||||
- `remote_access_user` (String) User name to use when connecting via remote access (RDP or SSH).
|
||||
|
||||
|
||||
<a id="nestedatt--images--distribution_surcharges"></a>
|
||||
### Nested Schema for `images.distribution_surcharges`
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `surcharge_base_cost` (Number) The additional cost for using this operating system as the base image for a size.
|
||||
- `surcharge_min_vcpu` (Number) The minimum vcpu count for surcharge calculations.
|
||||
- `surcharge_per_memory_max_megabytes` (Number) The maximum memory in MB that counts towards the surcharge_per_memory_mb. Any memory above this cap does not attract the surcharge.
|
||||
- `surcharge_per_memory_megabyte` (Number) The additional cost per MB for using this operating system as the base image for a size.
|
||||
- `surcharge_per_vcpu` (Number) The additional cost per vcpu for using this operating system as the base image for a size.
|
||||
@@ -3,14 +3,20 @@
|
||||
page_title: "binarylane_load_balancer Data Source - terraform-provider-binarylane"
|
||||
subcategory: ""
|
||||
description: |-
|
||||
|
||||
Retrieve details about a BinaryLane Load Balancer.
|
||||
---
|
||||
|
||||
# binarylane_load_balancer (Data Source)
|
||||
|
||||
Retrieve details about a BinaryLane Load Balancer.
|
||||
|
||||
## Example Usage
|
||||
|
||||
|
||||
```terraform
|
||||
data "binarylane_load_balancer" "example" {
|
||||
id = 123456
|
||||
}
|
||||
```
|
||||
|
||||
<!-- schema generated by tfplugindocs -->
|
||||
## Schema
|
||||
@@ -21,8 +27,9 @@ description: |-
|
||||
|
||||
### Read-Only
|
||||
|
||||
- `forwarding_rules` (List of Object) The rules that control which traffic the load balancer will forward to servers in the pool. Leave null to accept a default "HTTP" only forwarding rule. (see [below for nested schema](#nestedatt--forwarding_rules))
|
||||
- `forwarding_rules` (Attributes List) The rules that control which traffic the load balancer will forward to servers in the pool. Leave null to accept a default "HTTP" only forwarding rule. (see [below for nested schema](#nestedatt--forwarding_rules))
|
||||
- `health_check` (Object) The rules that determine which servers are considered 'healthy' and in the server pool for the load balancer. Leave this null to accept appropriate defaults based on the forwarding_rules. (see [below for nested schema](#nestedatt--health_check))
|
||||
- `ip` (String) The IPv4 address of the load balancer.
|
||||
- `name` (String) The hostname of the load balancer.
|
||||
- `region` (String) Leave null to create an anycast load balancer.
|
||||
- `server_ids` (List of Number) A list of server IDs to assign to this load balancer.
|
||||
@@ -32,7 +39,12 @@ description: |-
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `entry_protocol` (String)
|
||||
- `entry_protocol` (String) The protocol that traffic must match for this load balancer to forward traffic according to this rule.
|
||||
|
||||
| Value | Description |
|
||||
| ----- | ----------- |
|
||||
| http | The load balancer will forward HTTP traffic that matches this rule. |
|
||||
| https | The load balancer will forward HTTPS traffic that matches this rule. |
|
||||
|
||||
|
||||
<a id="nestedatt--health_check"></a>
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
---
|
||||
# generated by https://github.com/hashicorp/terraform-plugin-docs
|
||||
page_title: "binarylane_regions Data Source - terraform-provider-binarylane"
|
||||
subcategory: ""
|
||||
description: |-
|
||||
|
||||
---
|
||||
|
||||
# binarylane_regions (Data Source)
|
||||
|
||||
|
||||
|
||||
## Example Usage
|
||||
|
||||
```terraform
|
||||
data "binarylane_regions" "example" {
|
||||
}
|
||||
```
|
||||
|
||||
<!-- schema generated by tfplugindocs -->
|
||||
## Schema
|
||||
|
||||
### Read-Only
|
||||
|
||||
- `regions` (Attributes List) (see [below for nested schema](#nestedatt--regions))
|
||||
|
||||
<a id="nestedatt--regions"></a>
|
||||
### Nested Schema for `regions`
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `available` (Boolean) Whether this region is available for the allocation of new resources.
|
||||
- `features` (List of String) A list of features available for resources in this region.
|
||||
- `name` (String) The name of this region.
|
||||
- `name_servers` (List of String) A list of nameservers available for resources in this region.
|
||||
- `sizes` (List of String) The slugs of the sizes available in this region.
|
||||
- `slug` (String) The unique slug for this region.
|
||||
@@ -3,14 +3,20 @@
|
||||
page_title: "binarylane_server Data Source - terraform-provider-binarylane"
|
||||
subcategory: ""
|
||||
description: |-
|
||||
Provides a Binary Lane Server data source. This can be used to read existing server details.
|
||||
Retrieve details about a BinaryLane Server.
|
||||
---
|
||||
|
||||
# binarylane_server (Data Source)
|
||||
|
||||
Provides a Binary Lane Server data source. This can be used to read existing server details.
|
||||
Retrieve details about a BinaryLane Server.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```terraform
|
||||
data "binarylane_server" "example" {
|
||||
id = 123456
|
||||
}
|
||||
```
|
||||
|
||||
<!-- schema generated by tfplugindocs -->
|
||||
## Schema
|
||||
@@ -21,15 +27,45 @@ Provides a Binary Lane Server data source. This can be used to read existing ser
|
||||
|
||||
### Read-Only
|
||||
|
||||
- `backups` (Boolean) If true this will enable two daily backups for the server. `options.daily_backups` will override this value if provided. Setting this to false has no effect.
|
||||
- `image` (String) The slug of the selected operating system.
|
||||
- `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.
|
||||
- `ipv6` (Boolean) If `true` this will add a public and private IPv6 address to the server. By default, IPv6 is disabled.
|
||||
- `memory` (Number) The total memory in MB for this server. Leave null to accept the default size. Valid values:
|
||||
- must be a multiple of 128
|
||||
- \> 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.
|
||||
- `private_ipv6_addresses` (List of String) The private IPv6 addresses assigned to the server.
|
||||
- `public_ipv4_addresses` (List of String) The public IPv4 addresses assigned to the server.
|
||||
- `public_ipv6_addresses` (List of String) The public IPv6 addresses assigned to the server.
|
||||
- `region` (String) The slug of the selected region.
|
||||
- `size` (String) The slug of the selected size.
|
||||
- `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) If provided this will be used to initialise the new server. This must be left null if the Image does not support UserData, see DistributionInfo.Features for more information.
|
||||
- `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)
|
||||
|
||||
@@ -3,14 +3,20 @@
|
||||
page_title: "binarylane_server_firewall_rules Data Source - terraform-provider-binarylane"
|
||||
subcategory: ""
|
||||
description: |-
|
||||
TODO
|
||||
Retrieve details about the External Firewall Rules assigned to a BinaryLane server.
|
||||
---
|
||||
|
||||
# binarylane_server_firewall_rules (Data Source)
|
||||
|
||||
TODO
|
||||
Retrieve details about the External Firewall Rules assigned to a BinaryLane server.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```terraform
|
||||
data "binarylane_server_firewall_rules" "example" {
|
||||
server_id = 123456
|
||||
}
|
||||
```
|
||||
|
||||
<!-- schema generated by tfplugindocs -->
|
||||
## Schema
|
||||
@@ -21,16 +27,28 @@ TODO
|
||||
|
||||
### Read-Only
|
||||
|
||||
- `firewall_rules` (List of Object) A list of rules for the server. NB: that any existing rules that are not included will be removed. Submit an empty list to clear all rules. (see [below for nested schema](#nestedatt--firewall_rules))
|
||||
- `firewall_rules` (Attributes List) A list of rules for the server. NB: that any existing rules that are not included will be removed. Submit an empty list to clear all rules. (see [below for nested schema](#nestedatt--firewall_rules))
|
||||
|
||||
<a id="nestedatt--firewall_rules"></a>
|
||||
### Nested Schema for `firewall_rules`
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `action` (String)
|
||||
- `description` (String)
|
||||
- `destination_addresses` (List of String)
|
||||
- `destination_ports` (List of String)
|
||||
- `protocol` (String)
|
||||
- `source_addresses` (List of String)
|
||||
- `action` (String) The action to take when there is a match on this rule.
|
||||
|
||||
| Value | Description |
|
||||
| ----- | ----------- |
|
||||
| drop | Traffic matching this rule will be dropped. |
|
||||
| accept | Traffic matching this rule will be accepted. |
|
||||
- `description` (String) A description to assist in identifying this rule. Commonly used to record the reason for the rule or the intent behind it, e.g. "Block access to RDP" or "Allow access from HQ".
|
||||
- `destination_addresses` (List of String) The destination addresses to match for this rule. Each address may be an individual IPv4 address or a range in IPv4 CIDR notation.
|
||||
- `destination_ports` (List of String) The destination ports to match for this rule. Leave null or empty to match on all ports.
|
||||
- `protocol` (String) The protocol to match for this rule.
|
||||
|
||||
| Value | Description |
|
||||
| ----- | ----------- |
|
||||
| all | This rule will match any protocol. |
|
||||
| icmp | This rule will match ICMP traffic only. |
|
||||
| tcp | This rule will match TCP traffic only. |
|
||||
| udp | This rule will match UDP traffic only. |
|
||||
- `source_addresses` (List of String) The source addresses to match for this rule. Each address may be an individual IPv4 address or a range in IPv4 CIDR notation.
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
---
|
||||
# generated by https://github.com/hashicorp/terraform-plugin-docs
|
||||
page_title: "binarylane_sizes Data Source - terraform-provider-binarylane"
|
||||
subcategory: ""
|
||||
description: |-
|
||||
|
||||
---
|
||||
|
||||
# binarylane_sizes (Data Source)
|
||||
|
||||
|
||||
|
||||
## Example Usage
|
||||
|
||||
```terraform
|
||||
data "binarylane_sizes" "example" {
|
||||
}
|
||||
```
|
||||
|
||||
<!-- schema generated by tfplugindocs -->
|
||||
## Schema
|
||||
|
||||
### Optional
|
||||
|
||||
- `image` (String) If null or not provided regions that support the size are included in the returned objects regardless of operating system. If this is provided it must be the id or slug of an operating system image and will cause only valid regions for the size and operating system to be included in the returned objects.
|
||||
- `server_id` (Number) If supplied only sizes available for a resize the specified server will be returned. This parameter is only available when authenticated.
|
||||
|
||||
### Read-Only
|
||||
|
||||
- `sizes` (Attributes List) (see [below for nested schema](#nestedatt--sizes))
|
||||
|
||||
<a id="nestedatt--sizes"></a>
|
||||
### Nested Schema for `sizes`
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `available` (Boolean) If this is false the size is not available for new servers.
|
||||
- `cpu_description` (String) A description of the CPU provided in this size.
|
||||
- `description` (String) A description of this size.
|
||||
- `disk` (Number) The included storage for this size in GB.
|
||||
- `excess_transfer_cost_per_gigabyte` (Number) The excess charged for any transfer above the included data transfer in AU$ per GB.
|
||||
- `memory` (Number) The included memory for this size in MB.
|
||||
- `options` (Attributes) Available add-ons (optional features not included in the base price) for the size. All costs are in AU$ per month (pro-rated). (see [below for nested schema](#nestedatt--sizes--options))
|
||||
- `price_hourly` (Number) Hourly price in AU$.
|
||||
- `price_monthly` (Number) Monthly Price in AU$.
|
||||
- `regions` (List of String) A list of region slugs where this size is available regardless of stock.
|
||||
If this a response to a query that included a selected operating system this response will only include regions where that operating system is available on this size,
|
||||
otherwise not all regions listed will support all operating systems on this size.
|
||||
- `regions_out_of_stock` (List of String) A list of region slugs where the size is normally available but is currently not available due to lack of stock.
|
||||
- `size_type` (Attributes) The type of this size, generally used to differentiate sizes optimized for different usages. (see [below for nested schema](#nestedatt--sizes--size_type))
|
||||
- `slug` (String) The slug of this size.
|
||||
- `storage_description` (String) A description of the storage provided in this size.
|
||||
- `transfer` (Number) The included data transfer for this size in TB.
|
||||
- `vcpu_units` (String) This is the unit that the vcpus field counts, e.g. "core" or "thread".
|
||||
- `vcpus` (Number) The count of virtual CPUs for this size. See vcpu_units for a description of how each virtual CPU maps to the underlying hardware.
|
||||
|
||||
<a id="nestedatt--sizes--options"></a>
|
||||
### Nested Schema for `sizes.options`
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `backups_cost_per_backup_per_gigabyte` (Number) The cost per GB of storage of each selected backup. See the API support document for how to calculate the final cost of backups based on the options selected.
|
||||
- `daily_backups` (Number) The number of daily backups included in the base size cost.
|
||||
- `discount_for_no_public_ipv4` (Number) This is the discount (if any) that is applied if no public IPv4 addresses are selected.
|
||||
- `disk_cost_per_additional_gigabyte` (Number) The additional cost per GB per month for additional storage space.
|
||||
- `disk_max` (Number) The maximum storage in GB permitted on this size.
|
||||
- `disk_min` (Number) The minimum storage in GB permitted on this size.
|
||||
- `ipv4_addresses_cost_per_address` (Number) The additional cost per public IPv4 address per month for additional IPv4 addresses.
|
||||
- `ipv4_addresses_max` (Number) The maximum number of IPv4 addresses permitted on this size.
|
||||
- `memory_cost_per_additional_megabyte` (Number) The additional cost per MB per month for additional memory.
|
||||
- `memory_max` (Number) The maximum memory in MB permitted on this size.
|
||||
- `monthly_backups` (Number) The number of monthly backups included in the base size cost.
|
||||
- `offsite_backup_frequency_cost` (Attributes) The additional cost per GB of storage for enabling offsite backups based on highest frequency of backups currently enabled. All costs are in AU$. (see [below for nested schema](#nestedatt--sizes--options--offsite_backup_frequency_cost))
|
||||
- `offsite_backups_cost_per_gigabyte` (Number) The additional cost per GB of storage for enabling offsite backups. See the API support document for how to calculate the final cost of backups based on the options selected.
|
||||
- `restricted_disk_values` (List of Number) If this is null the normal valid values in the documentation for SizeOptionsRequest are used, otherwise only these values (in GB) are permitted.
|
||||
- `transfer_cost_per_additional_gigabyte` (Number) The additional cost per GB per month for additional included transfer.
|
||||
- `transfer_max` (Number) The maximum transfer in TB permitted for this size.
|
||||
- `weekly_backups` (Number) The number of weekly backups included in the base size cost.
|
||||
|
||||
<a id="nestedatt--sizes--options--offsite_backup_frequency_cost"></a>
|
||||
### Nested Schema for `sizes.options.offsite_backup_frequency_cost`
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `daily_per_gigabyte` (Number) The additional cost per GB per month for enabling daily offsite backups. Only the highest value of the daily, weekly and monthly is applied. See the API support document for how to calculate the final cost of backups based on the options selected.
|
||||
- `monthly_per_gigabyte` (Number) The additional cost per GB per month for enabling monthly offsite backups. Only the highest value of the daily, weekly and monthly is applied. See the API support document for how to calculate the final cost of backups based on the options selected.
|
||||
- `weekly_per_gigabyte` (Number) The additional cost per GB per month for enabling weekly offsite backups. Only the highest value of the daily, weekly and monthly is applied. See the API support document for how to calculate the final cost of backups based on the options selected.
|
||||
|
||||
|
||||
|
||||
<a id="nestedatt--sizes--size_type"></a>
|
||||
### Nested Schema for `sizes.size_type`
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `description` (String) The description of this size type, generally used to indicate the intended use case for sizes of this type.
|
||||
- `name` (String) The name of this size type.
|
||||
- `slug` (String) The slug of this size type.
|
||||
@@ -10,7 +10,13 @@ description: |-
|
||||
|
||||
|
||||
|
||||
## Example Usage
|
||||
|
||||
```terraform
|
||||
data "binarylane_ssh_key" "example" {
|
||||
id = 123456
|
||||
}
|
||||
```
|
||||
|
||||
<!-- schema generated by tfplugindocs -->
|
||||
## Schema
|
||||
@@ -21,7 +27,7 @@ description: |-
|
||||
|
||||
### Read-Only
|
||||
|
||||
- `default` (Boolean) Optional: If true this will be added to all new server installations (if we support SSH Key injection for the server's operating system).
|
||||
- `default` (Boolean) If `true`, this SSH key will be included on all new server installations (if the operating system supports SSH key injection).
|
||||
- `fingerprint` (String) The fingerprint of the SSH key.
|
||||
- `name` (String) A name to help you identify the key.
|
||||
- `public_key` (String) The public key in OpenSSH "authorized_keys" format.
|
||||
- `public_key` (String) The public key in OpenSSH "authorized_keys" format. This should be a valid public key, such as one generated by `ssh-keygen`.
|
||||
|
||||
@@ -10,7 +10,13 @@ description: |-
|
||||
|
||||
|
||||
|
||||
## Example Usage
|
||||
|
||||
```terraform
|
||||
data "binarylane_vpc" "example" {
|
||||
id = 123456
|
||||
}
|
||||
```
|
||||
|
||||
<!-- schema generated by tfplugindocs -->
|
||||
## Schema
|
||||
|
||||
@@ -10,7 +10,13 @@ description: |-
|
||||
|
||||
|
||||
|
||||
## Example Usage
|
||||
|
||||
```terraform
|
||||
data "binarylane_vpc_route_entries" "example" {
|
||||
vpc_id = 123456
|
||||
}
|
||||
```
|
||||
|
||||
<!-- schema generated by tfplugindocs -->
|
||||
## Schema
|
||||
@@ -21,13 +27,13 @@ description: |-
|
||||
|
||||
### Read-Only
|
||||
|
||||
- `route_entries` (List of Object) Submit null to leave unaltered, submit an empty list to clear all route entries. It is not possible to PATCH individual route entries, to alter a route entry submit the entire list of route entries you wish to save. (see [below for nested schema](#nestedatt--route_entries))
|
||||
- `route_entries` (Attributes List) The route entries that control how network traffic is directed through the VPC environment. (see [below for nested schema](#nestedatt--route_entries))
|
||||
|
||||
<a id="nestedatt--route_entries"></a>
|
||||
### Nested Schema for `route_entries`
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `description` (String)
|
||||
- `destination` (String)
|
||||
- `router` (String)
|
||||
- `description` (String) An optional description for the route.
|
||||
- `destination` (String) The destination address for this route entry. This may be in CIDR format.
|
||||
- `router` (String) The server that will receive traffic sent to the destination property in this VPC.
|
||||
|
||||
+18
-3
@@ -1,7 +1,6 @@
|
||||
---
|
||||
# generated by https://github.com/hashicorp/terraform-plugin-docs
|
||||
page_title: "binarylane Provider"
|
||||
subcategory: ""
|
||||
description: |-
|
||||
|
||||
---
|
||||
@@ -10,12 +9,28 @@ description: |-
|
||||
|
||||
|
||||
|
||||
## Example Usage
|
||||
|
||||
```terraform
|
||||
terraform {
|
||||
required_providers {
|
||||
binarylane = {
|
||||
source = "oscarhermoso/binarylane"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "binarylane" {
|
||||
api_token = var.binarylane_api_token
|
||||
|
||||
# Or, set environment variable BINARYLANE_API_TOKEN
|
||||
}
|
||||
```
|
||||
|
||||
<!-- schema generated by tfplugindocs -->
|
||||
## Schema
|
||||
|
||||
### Optional
|
||||
|
||||
- `api_endpoint` (String) Binary Lane API endpoint. If not set checks env for `BINARYLANE_API_ENDPOINT`. Default: `https://api.binarylane.com.au/v2`.
|
||||
- `api_token` (String, Sensitive) Binary Lane API token. If not set checks env for `BINARYLANE_API_TOKEN`.
|
||||
- `api_endpoint` (String) Binary Lane API endpoint. Defaults to `https://api.binarylane.com.au/v2`, but can be overridden by setting this attribute or the `BINARYLANE_API_ENDPOINT` environment variable.
|
||||
- `api_token` (String, Sensitive) Binary Lane API token. If not defined, will default to `BINARYLANE_API_TOKEN` environment variable.
|
||||
|
||||
@@ -3,14 +3,30 @@
|
||||
page_title: "binarylane_load_balancer Resource - terraform-provider-binarylane"
|
||||
subcategory: ""
|
||||
description: |-
|
||||
|
||||
Provides a BinaryLane Load Balancer resource. This can be used to create, update, and delete load balancers. See the docs https://support.binarylane.com.au/support/solutions/articles/1000025661-load-balancer for more information.
|
||||
---
|
||||
|
||||
# binarylane_load_balancer (Resource)
|
||||
|
||||
Provides a BinaryLane Load Balancer resource. This can be used to create, update, and delete load balancers. See [the docs](https://support.binarylane.com.au/support/solutions/articles/1000025661-load-balancer) for more information.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```terraform
|
||||
resource "binarylane_server" "example" {
|
||||
count = 2
|
||||
# ...
|
||||
}
|
||||
|
||||
resource "binarylane_load_balancer" "example" {
|
||||
name = "tf-example-lb"
|
||||
forwarding_rules = [{ entry_protocol = "https" }]
|
||||
server_ids = [
|
||||
binarylane_server.example.0.id,
|
||||
binarylane_server.example.1.id
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
<!-- schema generated by tfplugindocs -->
|
||||
## Schema
|
||||
@@ -30,6 +46,7 @@ description: |-
|
||||
### Read-Only
|
||||
|
||||
- `id` (Number) The ID of the load balancer to fetch.
|
||||
- `ip` (String) The IPv4 address of the load balancer.
|
||||
|
||||
<a id="nestedatt--forwarding_rules"></a>
|
||||
### Nested Schema for `forwarding_rules`
|
||||
@@ -38,6 +55,11 @@ Required:
|
||||
|
||||
- `entry_protocol` (String) The protocol that traffic must match for this load balancer to forward traffic according to this rule.
|
||||
|
||||
| Value | Description |
|
||||
| ----- | ----------- |
|
||||
| http | The load balancer will forward HTTP traffic that matches this rule. |
|
||||
| https | The load balancer will forward HTTPS traffic that matches this rule. |
|
||||
|
||||
|
||||
<a id="nestedatt--health_check"></a>
|
||||
### Nested Schema for `health_check`
|
||||
@@ -47,6 +69,12 @@ Optional:
|
||||
- `path` (String) Leave null to accept the default '/' path.
|
||||
- `protocol` (String) Leave null to accept the default HTTP protocol.
|
||||
|
||||
| Value | Description |
|
||||
| ----- | ----------- |
|
||||
| http | The health check will be performed via HTTP. |
|
||||
| https | The health check will be performed via HTTPS. |
|
||||
| both | The health check will be performed via both HTTP and HTTPS. Failing a health check on one protocol will remove the server from the pool of servers only for that protocol. |
|
||||
|
||||
|
||||
<a id="nestedatt--timeouts"></a>
|
||||
### Nested Schema for `timeouts`
|
||||
@@ -54,3 +82,13 @@ Optional:
|
||||
Optional:
|
||||
|
||||
- `create` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours).
|
||||
|
||||
## Import
|
||||
|
||||
Import is supported using the following syntax:
|
||||
|
||||
The [`terraform import` command](https://developer.hashicorp.com/terraform/cli/commands/import) can be used, for example:
|
||||
|
||||
```shell
|
||||
terraform import binarylane_load_balancer.example "<name or id>"
|
||||
```
|
||||
|
||||
@@ -3,34 +3,60 @@
|
||||
page_title: "binarylane_server Resource - terraform-provider-binarylane"
|
||||
subcategory: ""
|
||||
description: |-
|
||||
Provides a Binary Lane Server resource. This can be used to create and delete servers.
|
||||
|
||||
---
|
||||
|
||||
# binarylane_server (Resource)
|
||||
|
||||
Provides a Binary Lane Server resource. This can be used to create and delete servers.
|
||||
|
||||
|
||||
## Example Usage
|
||||
|
||||
```terraform
|
||||
resource "binarylane_server" "example" {
|
||||
name = "tf-example"
|
||||
region = "per" # or "syd", "mel", "bne", "sin"
|
||||
image = "ubuntu-24.04"
|
||||
size = "std-min" # 1 VPCU, 1 GB Memory, 20 GB NVME Storage, 1000 GB Data Transfer
|
||||
public_ipv4_count = 1
|
||||
|
||||
# Accepts a cloud-init script or cloud-config YAML file to configure the server
|
||||
# See more: https://cloudinit.readthedocs.io/en/latest/explanation/format.html#user-data-script
|
||||
user_data = file("./init.sh")
|
||||
}
|
||||
```
|
||||
|
||||
<!-- schema generated by tfplugindocs -->
|
||||
## Schema
|
||||
|
||||
### Required
|
||||
|
||||
- `image` (String) The slug of the selected operating system.
|
||||
- `public_ipv4_count` (Number) The number of public IPv4 addresses to assign to the server. If this is not provided, the server will be created with the default number of public IPv4 addresses.
|
||||
- `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.
|
||||
- `public_ipv4_count` (Number) The number of public IPv4 addresses to assign to the server.
|
||||
- `region` (String) The slug of the selected region.
|
||||
- `size` (String) The slug of the selected size.
|
||||
|
||||
### Optional
|
||||
|
||||
- `backups` (Boolean) If true this will enable two daily backups for the server. `options.daily_backups` will override this value if provided. Setting this to false has no effect.
|
||||
- `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
|
||||
- \> 60 GB must be a multiple of 10
|
||||
- \> 200 GB must be a multiple of 100
|
||||
- `ipv6` (Boolean) If `true` this will add a public and private IPv6 address to the server. By default, IPv6 is disabled.
|
||||
- `memory` (Number) The total memory in MB for this server. Leave null to accept the default size. Valid values:
|
||||
- must be a multiple of 128
|
||||
- \> 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.
|
||||
- `password` (String, Sensitive) If this is provided the specified or default remote user's account password will be set to this value. Only valid if the server supports password change actions. If omitted and the server supports password change actions a random password will be generated and emailed to the account email address.
|
||||
- `port_blocking` (Boolean) Port blocking of outgoing connections for email, SSH and Remote Desktop (TCP ports 22, 25, and 3389) is enabled by default for all new servers. If this is false port blocking will be disabled. Disabling port blocking is only available to reviewed accounts.
|
||||
- `source_and_destination_check` (Boolean) This attribute can only be set if your server also has a `vpc_id` attribute set. When enabled (which is `true` by default), your server will only be able to send or receive packets that are directly addressed to one of the IP addresses associated with the Cloud Server. Generally, this is desirable behaviour because it prevents IP conflicts and other hard-to-diagnose networking faults due to incorrect network configuration. When `source_and_destination_check` is `false`, your Cloud Server will be able to send and receive packets addressed to any server. This is typically used when you want to use your Cloud Server as a VPN endpoint, a NAT server to provide internet access, or IP forwarding.
|
||||
- `ssh_keys` (List of Number) This is a list of SSH key ids. If this is null or not provided, any SSH keys that have been marked as default will be deployed (assuming the operating system supports SSH Keys). Submit an empty list to disable deployment of default keys.
|
||||
- `timeouts` (Attributes) (see [below for nested schema](#nestedatt--timeouts))
|
||||
- `user_data` (String) If provided this will be used to initialise the new server. This must be left null if the Image does not support UserData, see DistributionInfo.Features for more information.
|
||||
- `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.
|
||||
|
||||
### Read-Only
|
||||
@@ -39,7 +65,29 @@ Provides a Binary Lane Server resource. This can be used to create and delete se
|
||||
- `password_change_supported` (Boolean) 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.
|
||||
- `permalink` (String) A randomly generated two-word identifier assigned to servers in regions that support this feature
|
||||
- `private_ipv4_addresses` (List of String) The private IPv4 addresses assigned to the server.
|
||||
- `private_ipv6_addresses` (List of String) The private IPv6 addresses assigned to the server.
|
||||
- `public_ipv4_addresses` (List of String) The public IPv4 addresses assigned to the server.
|
||||
- `public_ipv6_addresses` (List of String) The public IPv6 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`
|
||||
@@ -48,3 +96,13 @@ Optional:
|
||||
|
||||
- `create` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours).
|
||||
- `update` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours).
|
||||
|
||||
## Import
|
||||
|
||||
Import is supported using the following syntax:
|
||||
|
||||
The [`terraform import` command](https://developer.hashicorp.com/terraform/cli/commands/import) can be used, for example:
|
||||
|
||||
```shell
|
||||
terraform import binarylane_server.example "<server name or id>"
|
||||
```
|
||||
|
||||
@@ -3,14 +3,34 @@
|
||||
page_title: "binarylane_server_firewall_rules Resource - terraform-provider-binarylane"
|
||||
subcategory: ""
|
||||
description: |-
|
||||
|
||||
Retrieve details about the External Firewall Rules assigned to a BinaryLane server.
|
||||
---
|
||||
|
||||
# binarylane_server_firewall_rules (Resource)
|
||||
|
||||
Retrieve details about the External Firewall Rules assigned to a BinaryLane server.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```terraform
|
||||
resource "binarylane_server" "example" {
|
||||
# ...
|
||||
}
|
||||
|
||||
resource "binarylane_server_firewall_rules" "example" {
|
||||
server_id = binarylane_server.example.id
|
||||
firewall_rules = [
|
||||
{
|
||||
description = "Allow SSH"
|
||||
protocol = "tcp"
|
||||
source_addresses = ["0.0.0.0/0"]
|
||||
destination_addresses = [binarylane_server.example.private_ipv4_addresses.0]
|
||||
destination_ports = ["22"]
|
||||
action = "accept"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
<!-- schema generated by tfplugindocs -->
|
||||
## Schema
|
||||
@@ -26,11 +46,33 @@ description: |-
|
||||
Required:
|
||||
|
||||
- `action` (String) The action to take when there is a match on this rule.
|
||||
|
||||
| Value | Description |
|
||||
| ----- | ----------- |
|
||||
| drop | Traffic matching this rule will be dropped. |
|
||||
| accept | Traffic matching this rule will be accepted. |
|
||||
- `destination_addresses` (List of String) The destination addresses to match for this rule. Each address may be an individual IPv4 address or a range in IPv4 CIDR notation.
|
||||
- `protocol` (String) The protocol to match for this rule.
|
||||
|
||||
| Value | Description |
|
||||
| ----- | ----------- |
|
||||
| all | This rule will match any protocol. |
|
||||
| icmp | This rule will match ICMP traffic only. |
|
||||
| tcp | This rule will match TCP traffic only. |
|
||||
| udp | This rule will match UDP traffic only. |
|
||||
- `source_addresses` (List of String) The source addresses to match for this rule. Each address may be an individual IPv4 address or a range in IPv4 CIDR notation.
|
||||
|
||||
Optional:
|
||||
|
||||
- `description` (String) A description to assist in identifying this rule. Commonly used to record the reason for the rule or the intent behind it, e.g. "Block access to RDP" or "Allow access from HQ".
|
||||
- `destination_ports` (List of String) The destination ports to match for this rule. Leave null or empty to match on all ports.
|
||||
|
||||
## Import
|
||||
|
||||
Import is supported using the following syntax:
|
||||
|
||||
The [`terraform import` command](https://developer.hashicorp.com/terraform/cli/commands/import) can be used, for example:
|
||||
|
||||
```shell
|
||||
terraform import binarylane_server_firewall_rules.example "<server name or id>"
|
||||
```
|
||||
|
||||
@@ -10,7 +10,21 @@ description: |-
|
||||
|
||||
|
||||
|
||||
## Example Usage
|
||||
|
||||
```terraform
|
||||
resource "binarylane_ssh_key" "example" {
|
||||
name = "tf-example"
|
||||
|
||||
# Generate with: ssh-keygen -t ed25519 -C "name@example.com"
|
||||
public_key = file("~/.ssh/id_ed25519.pub")
|
||||
}
|
||||
|
||||
resource "binarylane_server" "example" {
|
||||
# ...
|
||||
ssh_keys = [binarylane_ssh_key.example.id]
|
||||
}
|
||||
```
|
||||
|
||||
<!-- schema generated by tfplugindocs -->
|
||||
## Schema
|
||||
@@ -18,13 +32,23 @@ description: |-
|
||||
### Required
|
||||
|
||||
- `name` (String) A name to help you identify the key.
|
||||
- `public_key` (String) The public key in OpenSSH "authorized_keys" format.
|
||||
- `public_key` (String) The public key in OpenSSH "authorized_keys" format. This should be a valid public key, such as one generated by `ssh-keygen`.
|
||||
|
||||
### Optional
|
||||
|
||||
- `default` (Boolean) Optional: If true this will be added to all new server installations (if we support SSH Key injection for the server's operating system).
|
||||
- `id` (Number) The ID or fingerprint of the SSH Key to fetch.
|
||||
- `default` (Boolean) If `true`, this SSH key will be included on all new server installations (if the operating system supports SSH key injection). Default is `false`.
|
||||
|
||||
### Read-Only
|
||||
|
||||
- `fingerprint` (String) The fingerprint of the SSH key.
|
||||
- `id` (Number) The numeric ID of the SSH key.
|
||||
|
||||
## Import
|
||||
|
||||
Import is supported using the following syntax:
|
||||
|
||||
The [`terraform import` command](https://developer.hashicorp.com/terraform/cli/commands/import) can be used, for example:
|
||||
|
||||
```shell
|
||||
terraform import binarylane_ssh_key.example "<SSH Key ID or fingerprint>"
|
||||
```
|
||||
|
||||
@@ -10,7 +10,19 @@ description: |-
|
||||
|
||||
|
||||
|
||||
## Example Usage
|
||||
|
||||
```terraform
|
||||
resource "binarylane_vpc" "example" {
|
||||
name = "tf-example-vpc"
|
||||
ip_range = "10.240.0.0/16"
|
||||
}
|
||||
|
||||
resource "binarylane_server" "example" {
|
||||
# ...
|
||||
vpc_id = binarylane_vpc.example.id
|
||||
}
|
||||
```
|
||||
|
||||
<!-- schema generated by tfplugindocs -->
|
||||
## Schema
|
||||
@@ -26,3 +38,13 @@ description: |-
|
||||
### Read-Only
|
||||
|
||||
- `id` (Number) The target vpc id.
|
||||
|
||||
## Import
|
||||
|
||||
Import is supported using the following syntax:
|
||||
|
||||
The [`terraform import` command](https://developer.hashicorp.com/terraform/cli/commands/import) can be used, for example:
|
||||
|
||||
```shell
|
||||
terraform import binarylane_vpc.example "<vpc_id>"
|
||||
```
|
||||
|
||||
@@ -10,7 +10,35 @@ description: |-
|
||||
|
||||
|
||||
|
||||
## Example Usage
|
||||
|
||||
```terraform
|
||||
resource "binarylane_vpc" "example" {
|
||||
name = "tf-example-vpc"
|
||||
ip_range = "10.240.0.0/16"
|
||||
}
|
||||
|
||||
resource "binarylane_server" "web" {
|
||||
# ...
|
||||
vpc_id = binarylane_vpc.example.id
|
||||
}
|
||||
|
||||
resource "binarylane_vpc_route_entries" "example" {
|
||||
vpc_id = binarylane_vpc.example.id
|
||||
route_entries = [
|
||||
{
|
||||
description = "NAT"
|
||||
destination = "0.0.0.0/0"
|
||||
router = binarylane_server.web.private_ipv4_addresses.0
|
||||
},
|
||||
{
|
||||
description = "VPN"
|
||||
destination = "192.168.1.0/24"
|
||||
router = binarylane_server.vpn.private_ipv4_addresses.0
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
<!-- schema generated by tfplugindocs -->
|
||||
## Schema
|
||||
@@ -34,3 +62,13 @@ Required:
|
||||
Optional:
|
||||
|
||||
- `description` (String) An optional description for the route.
|
||||
|
||||
## Import
|
||||
|
||||
Import is supported using the following syntax:
|
||||
|
||||
The [`terraform import` command](https://developer.hashicorp.com/terraform/cli/commands/import) can be used, for example:
|
||||
|
||||
```shell
|
||||
terraform import binarylane_vpc_route_entries.example "<vpc_id>"
|
||||
```
|
||||
|
||||
+2
-1
@@ -3,8 +3,9 @@
|
||||
In order of increasing complexity, these examples show how to use the provider.
|
||||
|
||||
- [./basic](./basic/main.tf) - A basic example that creates a server.
|
||||
- [./offerings](./offerings/main.tf) - Use data sources to list available images, regions, and sizes.
|
||||
- [./ssh](./ssh/main.tf) - Create a server and registers an SSH key as a global default.
|
||||
- [./cloud-init](./cloud-init/main.tf) - Create a server with a cloud-init configuration.
|
||||
- [./k3s](./k3s/main.tf) - Create Kubernetes cluster using k3s.
|
||||
- [./nix](./nix/main.tf) - WIP - Create a server with a NixOS configuration.
|
||||
- [./vpc](./vpc/main.tf) - WIP - Create a server with a Virtual Private Cloud.
|
||||
- [./k3s](./k3s/main.tf) - WIP - Create Kubernetes cluster using k3s.
|
||||
|
||||
@@ -3,10 +3,10 @@ bootcmd:
|
||||
# If you have additional installation steps that need to be awaited, define
|
||||
# these in the `bootcmd` section and they will also be awaited.
|
||||
#
|
||||
- [cloud-init-per, once, 'example-installing', sh, -c, 'sleep 60'] # pretend this is a slow installation step
|
||||
- [cloud-init-per, instance, 'example-installing', sh, -c, 'sleep 60'] # pretend this is a slow installation step
|
||||
- [
|
||||
cloud-init-per,
|
||||
once,
|
||||
instance,
|
||||
'example-done',
|
||||
sh,
|
||||
-c,
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
data "binarylane_images" "example" {
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
data "binarylane_load_balancer" "example" {
|
||||
id = 123456
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
data "binarylane_regions" "example" {
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
data "binarylane_server" "example" {
|
||||
id = 123456
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
data "binarylane_server_firewall_rules" "example" {
|
||||
server_id = 123456
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
data "binarylane_sizes" "example" {
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
data "binarylane_ssh_key" "example" {
|
||||
id = 123456
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
data "binarylane_vpc" "example" {
|
||||
id = 123456
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
data "binarylane_vpc_route_entries" "example" {
|
||||
vpc_id = 123456
|
||||
}
|
||||
@@ -38,3 +38,4 @@ terraform.rc
|
||||
|
||||
# .kube/config contains credentials
|
||||
.kube
|
||||
.id_ed25519*
|
||||
|
||||
+11
-8
@@ -1,15 +1,18 @@
|
||||
# WIP - examples/k8s
|
||||
# examples/k3s
|
||||
|
||||
This WIP example shows how to create a Kubernetes cluster on Binary Lane.
|
||||
This example shows how to create a K3s cluster on Binary Lane.
|
||||
|
||||
After setting up the cluster by running `terraform apply`, the kubeconfig file will be downloaded to the `.kube/config` file in the current directory. You can then use `kubectl` to interact with the cluster, for example:
|
||||
|
||||
The SSH key used to access the servers is stored in the `.id_ed25519` file. You can use it to SSH into the servers:
|
||||
|
||||
```sh
|
||||
ssh -o "IdentitiesOnly=yes" -i ./.id_ed25519 root@neptune-stand.bnr.la
|
||||
```
|
||||
|
||||
## Prior art
|
||||
|
||||
- [MartinHodges/create_k8s](https://github.com/MartinHodges/create_k8s) repo and the [medium article](https://medium.com/@martin.hodges/creating-a-kubernetes-cluster-from-scratch-in-1-hour-using-automation-a25e387be547) that goes with it.
|
||||
- https://github.com/inscapist/terraform-k3s-private-cloud
|
||||
- https://github.com/schnerring/schnerring.github.io/blob/07d06fb40e3d01f2483a739f516ac4d711a5742c/content/blog/use-terraform-to-deploy-an-azure-kubernetes-service-aks-cluster-traefik-2-cert-manager-and-lets-encrypt-certificates/index.md
|
||||
|
||||
## Remaining TODOs
|
||||
|
||||
- [ ] Consider rewriting module to use `microk8s` instead of `k3s`
|
||||
- [ ] Use `kustomize` instead of `helm`
|
||||
- [ ] Use the `binarylane_load_balancer` resource instead of `kubectl port-forward` (or use the load balancer in another example)
|
||||
- https://github.com/xunleii/terraform-module-k3s
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
#!/bin/bash -x
|
||||
exec >/tmp/k3s-agent-join-debug.log 2>&1
|
||||
|
||||
export K3S_TOKEN="${cluster_token}"
|
||||
export K3S_URL="https://${cluster_server}:6443"
|
||||
|
||||
curl -sfL https://get.k3s.io | sh -s - agent \
|
||||
--node-name="$(hostname -f)"
|
||||
|
||||
unset K3S_TOKEN
|
||||
unset K3S_URL
|
||||
|
||||
# Disable firewall recommended
|
||||
ufw disable
|
||||
|
||||
echo "K3s Node Join Completed"
|
||||
@@ -1,25 +0,0 @@
|
||||
#!/bin/bash -x
|
||||
exec >/tmp/k3s-server-install-debug.log 2>&1
|
||||
|
||||
export INSTALL_K3S_NAME="${cluster_id}"
|
||||
export K3S_TOKEN="${cluster_token}"
|
||||
export K3S_KUBECONFIG_MODE="644"
|
||||
|
||||
curl -sfL https://get.k3s.io | sh -s - server \
|
||||
--node-name="$(hostname -f)"
|
||||
# --disable-cloud-controller \
|
||||
# --disable servicelb \
|
||||
# --disable local-storage \
|
||||
# --disable traefik
|
||||
|
||||
unset INSTALL_K3S_NAME
|
||||
unset K3S_TOKEN
|
||||
unset K3S_KUBECONFIG_MODE
|
||||
|
||||
echo "Installing Helm"
|
||||
curl -sfL https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash
|
||||
|
||||
# Disable firewall recommended
|
||||
ufw disable
|
||||
|
||||
echo "K3s Setup Completed"
|
||||
@@ -0,0 +1,50 @@
|
||||
module "k3s" {
|
||||
# source = "xunleii/k3s/module" # Uncomment after https://github.com/xunleii/terraform-module-k3s/pull/207 is merged
|
||||
source = "github.com/dvdmuckle/terraform-module-k3s?ref=62dca7731b78f1120a141a2703e3ed14470276c0"
|
||||
|
||||
depends_on_ = binarylane_server.agents
|
||||
k3s_version = "latest"
|
||||
cluster_domain = "cluster.local"
|
||||
managed_fields = ["label"]
|
||||
|
||||
// These subnets are used by the Flannel network interface in K3s, and are NOT the same as the VPC address space
|
||||
cidr = {
|
||||
pods = "10.42.0.0/16",
|
||||
services = "10.43.0.0/16",
|
||||
}
|
||||
|
||||
servers = {
|
||||
for i in range(length(binarylane_server.servers)) :
|
||||
binarylane_server.servers[i].name => {
|
||||
ip = binarylane_server.servers[i].private_ipv4_addresses[0]
|
||||
name = binarylane_server.servers[i].name
|
||||
connection = {
|
||||
host = binarylane_server.servers[i].permalink
|
||||
private_key = trimspace(tls_private_key.ed25519_provisioning.private_key_pem)
|
||||
}
|
||||
labels = { "node.kubernetes.io/type" = "master" }
|
||||
flags = [
|
||||
"--tls-san ${binarylane_server.servers[0].private_ipv4_addresses[0]}",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
agents = {
|
||||
for i in range(length(binarylane_server.agents)) :
|
||||
binarylane_server.agents[i].name => {
|
||||
ip = binarylane_server.agents[i].private_ipv4_addresses[0]
|
||||
name = binarylane_server.agents[i].name
|
||||
connection = {
|
||||
host = binarylane_server.agents[i].permalink
|
||||
private_key = trimspace(tls_private_key.ed25519_provisioning.private_key_pem)
|
||||
}
|
||||
labels = { "node.kubernetes.io/pool" = "general" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "local_sensitive_file" "kube_config" {
|
||||
content = module.k3s.kube_config
|
||||
filename = ".kube/config"
|
||||
file_permission = "0644"
|
||||
}
|
||||
+28
-69
@@ -1,100 +1,60 @@
|
||||
locals {
|
||||
cluster_id = "tf-example-k8s"
|
||||
custom_domain = "tf-example-k8s.internal"
|
||||
cluster_id = "tf-example-k3s"
|
||||
custom_domain = "tf-example-k3s.internal"
|
||||
}
|
||||
|
||||
resource "random_password" "binarylane" {
|
||||
length = 18
|
||||
}
|
||||
|
||||
resource "random_password" "cluster_token" {
|
||||
length = 64
|
||||
special = false
|
||||
}
|
||||
|
||||
# SSH Key
|
||||
# -------
|
||||
resource "tls_private_key" "ed25519_provisioning" {
|
||||
algorithm = "ED25519"
|
||||
}
|
||||
|
||||
resource "local_sensitive_file" "ssh_private_key" {
|
||||
content = tls_private_key.ed25519_provisioning.private_key_openssh
|
||||
filename = ".id_ed25519"
|
||||
file_permission = "0600"
|
||||
}
|
||||
|
||||
resource "local_file" "ssh_public_key" {
|
||||
content = tls_private_key.ed25519_provisioning.public_key_openssh
|
||||
filename = ".id_ed25519.pub"
|
||||
file_permission = "0644"
|
||||
}
|
||||
|
||||
resource "binarylane_ssh_key" "example" {
|
||||
name = "tf-example-k8s"
|
||||
public_key = file("~/.ssh/id_ed25519.pub")
|
||||
name = "tf-example-k3s"
|
||||
public_key = tls_private_key.ed25519_provisioning.public_key_openssh
|
||||
}
|
||||
|
||||
# Virtual Private Cloud
|
||||
# ---------------------
|
||||
resource "binarylane_vpc" "example" {
|
||||
name = local.cluster_id
|
||||
ip_range = "10.240.0.0/16"
|
||||
ip_range = "10.0.0.0/8"
|
||||
}
|
||||
|
||||
# k3s Servers
|
||||
# -----------
|
||||
data "cloudinit_config" "server" {
|
||||
gzip = false
|
||||
base64_encode = false
|
||||
|
||||
part {
|
||||
content_type = "text/x-shellscript"
|
||||
content = templatefile("${path.module}/k3s-server-install.sh", {
|
||||
cluster_id = local.cluster_id,
|
||||
cluster_token = random_password.cluster_token.result,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
resource "binarylane_server" "server" {
|
||||
resource "binarylane_server" "servers" {
|
||||
count = 1
|
||||
|
||||
name = "${local.cluster_id}-server-${count.index + 1}"
|
||||
region = "per"
|
||||
image = "ubuntu-24.04"
|
||||
size = "std-min"
|
||||
size = "std-1vcpu" # 2GB memory, 1 vCPU
|
||||
password = random_password.binarylane.result
|
||||
ssh_keys = [binarylane_ssh_key.example.id]
|
||||
vpc_id = binarylane_vpc.example.id
|
||||
public_ipv4_count = 1
|
||||
user_data = sensitive(data.cloudinit_config.server.rendered)
|
||||
}
|
||||
|
||||
data "external" "kubeconfig" {
|
||||
program = [
|
||||
"/usr/bin/ssh",
|
||||
"-o UserKnownHostsFile=/dev/null",
|
||||
"-o StrictHostKeyChecking=no",
|
||||
"root@${binarylane_server.server.0.permalink}",
|
||||
"echo '{\"kubeconfig\":\"'$(cat /etc/rancher/k3s/k3s.yaml | base64)'\"}'",
|
||||
]
|
||||
}
|
||||
|
||||
resource "local_sensitive_file" "kubeconfig" {
|
||||
depends_on = [binarylane_server.server]
|
||||
|
||||
content = replace(
|
||||
base64decode(
|
||||
replace(data.external.kubeconfig.result.kubeconfig, " ", "")
|
||||
),
|
||||
"server: https://127.0.0.1:6443",
|
||||
"server: https://${binarylane_server.server.0.permalink}:6443",
|
||||
)
|
||||
filename = "${path.module}/.kube/config"
|
||||
file_permission = "0600"
|
||||
}
|
||||
|
||||
# k3s Agents
|
||||
# ----------
|
||||
data "cloudinit_config" "agent" {
|
||||
gzip = false
|
||||
base64_encode = false
|
||||
|
||||
part {
|
||||
content_type = "text/x-shellscript"
|
||||
content = templatefile("${path.module}/k3s-agent-join.sh", {
|
||||
cluster_token = random_password.cluster_token.result,
|
||||
cluster_server = binarylane_server.server.0.private_ipv4_addresses.0
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
resource "binarylane_server" "agent" {
|
||||
resource "binarylane_server" "agents" {
|
||||
count = 2
|
||||
|
||||
name = "${local.cluster_id}-agent-${count.index + 1}"
|
||||
@@ -105,12 +65,11 @@ resource "binarylane_server" "agent" {
|
||||
ssh_keys = [binarylane_ssh_key.example.id]
|
||||
vpc_id = binarylane_vpc.example.id
|
||||
public_ipv4_count = 1
|
||||
user_data = sensitive(data.cloudinit_config.agent.rendered)
|
||||
}
|
||||
|
||||
# Virtual Private Cloud Routing
|
||||
# -----------------------------
|
||||
resource "binarylane_vpc_route_entries" "example" {
|
||||
resource "binarylane_vpc_route_entries" "example" { # TODO
|
||||
vpc_id = binarylane_vpc.example.id
|
||||
route_entries = [
|
||||
# {
|
||||
@@ -122,12 +81,12 @@ resource "binarylane_vpc_route_entries" "example" {
|
||||
}
|
||||
|
||||
locals {
|
||||
agent_ips = flatten([for _, a in binarylane_server.agent : a.private_ipv4_addresses])
|
||||
server_ips = flatten([for _, s in binarylane_server.server : s.private_ipv4_addresses])
|
||||
agent_ips = flatten([for _, a in binarylane_server.agents : a.private_ipv4_addresses])
|
||||
server_ips = flatten([for _, s in binarylane_server.servers : s.private_ipv4_addresses])
|
||||
}
|
||||
|
||||
resource "binarylane_server_firewall_rules" "example" {
|
||||
for_each = { for server in concat(binarylane_server.server, binarylane_server.agent) : server.name => server }
|
||||
for_each = { for server in concat(binarylane_server.servers, binarylane_server.agents) : server.name => server }
|
||||
|
||||
server_id = each.value.id
|
||||
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
resource "kubectl_manifest" "hello" {
|
||||
yaml_body = <<YAML
|
||||
apiVersion: apps/v1
|
||||
kind: DaemonSet
|
||||
metadata:
|
||||
name: nginx-hello
|
||||
labels:
|
||||
app: nginx-hello
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx-hello
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx-hello
|
||||
spec:
|
||||
containers:
|
||||
- image: nginxdemos/hello
|
||||
name: nginx-hello
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 8080
|
||||
protocol: TCP
|
||||
YAML
|
||||
}
|
||||
|
||||
resource "kubectl_manifest" "hello_service" {
|
||||
yaml_body = <<YAML
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: nginx-hello
|
||||
labels:
|
||||
app: nginx-hello
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app: nginx-hello
|
||||
ports:
|
||||
- port: 80
|
||||
YAML
|
||||
}
|
||||
|
||||
resource "kubectl_manifest" "hello_ingress" {
|
||||
yaml_body = <<YAML
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: nginx-hello
|
||||
spec:
|
||||
rules:
|
||||
- host: "*.bnr.la"
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: nginx-hello
|
||||
port:
|
||||
number: 80
|
||||
YAML
|
||||
}
|
||||
@@ -3,25 +3,7 @@ terraform {
|
||||
binarylane = {
|
||||
source = "oscarhermoso/binarylane"
|
||||
}
|
||||
kubectl = {
|
||||
source = "alekc/kubectl"
|
||||
version = ">= 2.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "binarylane" {}
|
||||
|
||||
provider "helm" {
|
||||
kubernetes {
|
||||
host = "${binarylane_server.server.0.permalink}:6443"
|
||||
config_path = local_sensitive_file.kubeconfig.filename
|
||||
insecure = true # TODO
|
||||
}
|
||||
}
|
||||
|
||||
provider "kubectl" {
|
||||
host = "${binarylane_server.server.0.permalink}:6443"
|
||||
config_path = local_sensitive_file.kubeconfig.filename
|
||||
insecure = true # TODO
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
# Local .terraform directories
|
||||
**/.terraform/*
|
||||
|
||||
# .tfstate files
|
||||
*.tfstate
|
||||
*.tfstate.*
|
||||
|
||||
# Crash log files
|
||||
crash.log
|
||||
crash.*.log
|
||||
|
||||
# Exclude all .tfvars files, which are likely to contain sensitive data, such as
|
||||
# password, private keys, and other secrets. These should not be part of version
|
||||
# control as they are data points which are potentially sensitive and subject
|
||||
# to change depending on the environment.
|
||||
*.tfvars
|
||||
*.tfvars.json
|
||||
|
||||
# Ignore override files as they are usually used to override resources locally and so
|
||||
# are not checked in
|
||||
override.tf
|
||||
override.tf.json
|
||||
*_override.tf
|
||||
*_override.tf.json
|
||||
|
||||
# Ignore transient lock info files created by terraform apply
|
||||
.terraform.tfstate.lock.info
|
||||
|
||||
# Include override files you do wish to add to version control using negated pattern
|
||||
# !example_override.tf
|
||||
|
||||
# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
|
||||
# example: *tfplan*
|
||||
|
||||
# Ignore CLI configuration files
|
||||
.terraformrc
|
||||
terraform.rc
|
||||
@@ -0,0 +1,69 @@
|
||||
# examples/offerings
|
||||
|
||||
You can follow this example to list the available offerings for servers.
|
||||
|
||||
Feel free to customize this example further to filter by specific regions, operating systems, or server sizes to suit your needs.
|
||||
|
||||
|
||||
```sh
|
||||
terraform init
|
||||
terraform apply -refresh-only
|
||||
terraform output -json | jq -r 'with_entries(.value |= .value)'
|
||||
```
|
||||
|
||||
Example output:
|
||||
|
||||
```json
|
||||
{
|
||||
"images": [
|
||||
"alma-8",
|
||||
"alma-9",
|
||||
"byo-os",
|
||||
"byo-os-virtio-disabled",
|
||||
"debian-12",
|
||||
"ubuntu-20.04-neon-desktop",
|
||||
"rocky-8",
|
||||
"rocky-9",
|
||||
"ubuntu-22.04",
|
||||
"ubuntu-24.04",
|
||||
"cpanel-plus-whm",
|
||||
"debian-11",
|
||||
"ubuntu-20.04.6",
|
||||
"ubuntu-22.04-desktop",
|
||||
"windows-2022",
|
||||
"windows-2022-sql-2019-web",
|
||||
"windows-2022-sql-2019-std",
|
||||
"windows-2016",
|
||||
"windows-2019",
|
||||
"windows-2016-sql-2016-web",
|
||||
"windows-2019-sql-2017-web",
|
||||
"windows-2019-sql-2017-std"
|
||||
],
|
||||
"regions": [
|
||||
"syd",
|
||||
"mel",
|
||||
"bne",
|
||||
"per",
|
||||
"sin"
|
||||
],
|
||||
"sizes": [
|
||||
"std-min",
|
||||
"std-1vcpu",
|
||||
"std-2vcpu",
|
||||
"std-4vcpu",
|
||||
"std-6vcpu",
|
||||
"std-8vcpu",
|
||||
"cpu-2thr",
|
||||
"cpu-4thr",
|
||||
"cpu-6thr",
|
||||
"cpu-8thr",
|
||||
"hdd-500gb",
|
||||
"hdd-1000gb",
|
||||
"hdd-2000gb",
|
||||
"ded-e2136-400gb",
|
||||
"ded-e2136-800gb",
|
||||
"ded-e2288g-800gb",
|
||||
"ded-3900x-1600gb"
|
||||
]
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,29 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
binarylane = {
|
||||
source = "oscarhermoso/binarylane"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "binarylane" {
|
||||
# api_token = "" # Recommend setting with environment variable BINARYLANE_API_TOKEN
|
||||
}
|
||||
|
||||
data "binarylane_images" "example" {}
|
||||
|
||||
data "binarylane_sizes" "example" {}
|
||||
|
||||
data "binarylane_regions" "example" {}
|
||||
|
||||
output "images" {
|
||||
value = data.binarylane_images.example.images[*].slug
|
||||
}
|
||||
|
||||
output "sizes" {
|
||||
value = data.binarylane_sizes.example.sizes[*].slug
|
||||
}
|
||||
|
||||
output "regions" {
|
||||
value = data.binarylane_regions.example.regions[*].slug
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
binarylane = {
|
||||
source = "oscarhermoso/binarylane"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "binarylane" {
|
||||
api_token = var.binarylane_api_token
|
||||
|
||||
# Or, set environment variable BINARYLANE_API_TOKEN
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
terraform import binarylane_load_balancer.example "<name or id>"
|
||||
@@ -0,0 +1,13 @@
|
||||
resource "binarylane_server" "example" {
|
||||
count = 2
|
||||
# ...
|
||||
}
|
||||
|
||||
resource "binarylane_load_balancer" "example" {
|
||||
name = "tf-example-lb"
|
||||
forwarding_rules = [{ entry_protocol = "https" }]
|
||||
server_ids = [
|
||||
binarylane_server.example.0.id,
|
||||
binarylane_server.example.1.id
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
terraform import binarylane_server.example "<server name or id>"
|
||||
@@ -0,0 +1,11 @@
|
||||
resource "binarylane_server" "example" {
|
||||
name = "tf-example"
|
||||
region = "per" # or "syd", "mel", "bne", "sin"
|
||||
image = "ubuntu-24.04"
|
||||
size = "std-min" # 1 VPCU, 1 GB Memory, 20 GB NVME Storage, 1000 GB Data Transfer
|
||||
public_ipv4_count = 1
|
||||
|
||||
# Accepts a cloud-init script or cloud-config YAML file to configure the server
|
||||
# See more: https://cloudinit.readthedocs.io/en/latest/explanation/format.html#user-data-script
|
||||
user_data = file("./init.sh")
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
terraform import binarylane_server_firewall_rules.example "<server name or id>"
|
||||
@@ -0,0 +1,17 @@
|
||||
resource "binarylane_server" "example" {
|
||||
# ...
|
||||
}
|
||||
|
||||
resource "binarylane_server_firewall_rules" "example" {
|
||||
server_id = binarylane_server.example.id
|
||||
firewall_rules = [
|
||||
{
|
||||
description = "Allow SSH"
|
||||
protocol = "tcp"
|
||||
source_addresses = ["0.0.0.0/0"]
|
||||
destination_addresses = [binarylane_server.example.private_ipv4_addresses.0]
|
||||
destination_ports = ["22"]
|
||||
action = "accept"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
terraform import binarylane_ssh_key.example "<SSH Key ID or fingerprint>"
|
||||
@@ -0,0 +1,11 @@
|
||||
resource "binarylane_ssh_key" "example" {
|
||||
name = "tf-example"
|
||||
|
||||
# Generate with: ssh-keygen -t ed25519 -C "name@example.com"
|
||||
public_key = file("~/.ssh/id_ed25519.pub")
|
||||
}
|
||||
|
||||
resource "binarylane_server" "example" {
|
||||
# ...
|
||||
ssh_keys = [binarylane_ssh_key.example.id]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
terraform import binarylane_vpc.example "<vpc_id>"
|
||||
@@ -0,0 +1,9 @@
|
||||
resource "binarylane_vpc" "example" {
|
||||
name = "tf-example-vpc"
|
||||
ip_range = "10.240.0.0/16"
|
||||
}
|
||||
|
||||
resource "binarylane_server" "example" {
|
||||
# ...
|
||||
vpc_id = binarylane_vpc.example.id
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
terraform import binarylane_vpc_route_entries.example "<vpc_id>"
|
||||
@@ -0,0 +1,25 @@
|
||||
resource "binarylane_vpc" "example" {
|
||||
name = "tf-example-vpc"
|
||||
ip_range = "10.240.0.0/16"
|
||||
}
|
||||
|
||||
resource "binarylane_server" "web" {
|
||||
# ...
|
||||
vpc_id = binarylane_vpc.example.id
|
||||
}
|
||||
|
||||
resource "binarylane_vpc_route_entries" "example" {
|
||||
vpc_id = binarylane_vpc.example.id
|
||||
route_entries = [
|
||||
{
|
||||
description = "NAT"
|
||||
destination = "0.0.0.0/0"
|
||||
router = binarylane_server.web.private_ipv4_addresses.0
|
||||
},
|
||||
{
|
||||
description = "VPN"
|
||||
destination = "192.168.1.0/24"
|
||||
router = binarylane_server.vpn.private_ipv4_addresses.0
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -35,12 +35,13 @@ resource "binarylane_server" "db" {
|
||||
|
||||
# VPN server
|
||||
resource "binarylane_server" "vpn" {
|
||||
name = "tf-example-vpc-vpn"
|
||||
region = "per"
|
||||
image = "ubuntu-24.04"
|
||||
size = "std-min"
|
||||
vpc_id = binarylane_vpc.example.id
|
||||
public_ipv4_count = 1
|
||||
name = "tf-example-vpc-vpn"
|
||||
region = "per"
|
||||
image = "ubuntu-24.04"
|
||||
size = "std-min"
|
||||
vpc_id = binarylane_vpc.example.id
|
||||
public_ipv4_count = 1
|
||||
source_and_destination_check = false
|
||||
}
|
||||
|
||||
resource "binarylane_vpc_route_entries" "example" {
|
||||
|
||||
+5
-5
@@ -1,10 +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 ./provider-transform.sh
|
||||
//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
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
module terraform-provider-binarylane
|
||||
|
||||
go 1.22.7
|
||||
go 1.23.7
|
||||
|
||||
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.0
|
||||
github.com/hashicorp/terraform-plugin-framework v1.13.0
|
||||
github.com/hashicorp/terraform-plugin-framework-timeouts v0.4.1
|
||||
github.com/hashicorp/terraform-plugin-framework-validators v0.15.0
|
||||
github.com/hashicorp/terraform-plugin-go v0.25.0
|
||||
github.com/hashicorp/terraform-plugin-docs v0.22.0
|
||||
github.com/hashicorp/terraform-plugin-framework v1.15.1
|
||||
github.com/hashicorp/terraform-plugin-framework-timeouts v0.5.0
|
||||
github.com/hashicorp/terraform-plugin-framework-validators v0.18.0
|
||||
github.com/hashicorp/terraform-plugin-go v0.28.0
|
||||
github.com/hashicorp/terraform-plugin-log v0.9.0
|
||||
github.com/hashicorp/terraform-plugin-testing v1.10.0
|
||||
github.com/oapi-codegen/oapi-codegen/v2 v2.4.1
|
||||
github.com/oapi-codegen/runtime v1.1.1
|
||||
github.com/hashicorp/terraform-plugin-testing v1.13.3
|
||||
github.com/oapi-codegen/oapi-codegen/v2 v2.5.0
|
||||
github.com/oapi-codegen/runtime v1.1.2
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -23,53 +25,52 @@ 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.6 // 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/cloudflare/circl v1.6.1 // indirect
|
||||
github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect
|
||||
github.com/fatih/color v1.18.0 // indirect
|
||||
github.com/frankban/quicktest v1.14.6 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
||||
github.com/getkin/kin-openapi v0.127.0 // indirect
|
||||
github.com/getkin/kin-openapi v0.132.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||
github.com/go-openapi/swag v0.23.0 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/go-cmp v0.7.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
|
||||
github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 // indirect
|
||||
github.com/hashicorp/go-cty v1.5.0 // indirect
|
||||
github.com/hashicorp/go-hclog v1.6.3 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-plugin v1.6.2 // indirect
|
||||
github.com/hashicorp/go-plugin v1.6.3 // indirect
|
||||
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/hcl/v2 v2.21.0 // indirect
|
||||
github.com/hashicorp/hc-install v0.9.2 // 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.23.0 // indirect
|
||||
github.com/hashicorp/terraform-json v0.25.0 // indirect
|
||||
github.com/hashicorp/terraform-plugin-codegen-spec v0.2.0 // indirect
|
||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0 // indirect
|
||||
github.com/hashicorp/terraform-registry-address v0.2.3 // indirect
|
||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.37.0 // indirect
|
||||
github.com/hashicorp/terraform-registry-address v0.3.0 // indirect
|
||||
github.com/hashicorp/terraform-svchost v0.1.1 // indirect
|
||||
github.com/hashicorp/yamux v0.1.2 // indirect
|
||||
github.com/huandu/xstrings v1.4.0 // indirect
|
||||
github.com/imdario/mergo v0.3.16 // indirect
|
||||
github.com/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
|
||||
@@ -78,14 +79,17 @@ require (
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
|
||||
github.com/oklog/run v1.1.0 // indirect
|
||||
github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect
|
||||
github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect
|
||||
github.com/oklog/run v1.2.0 // indirect
|
||||
github.com/onsi/gomega v1.33.1 // indirect
|
||||
github.com/pb33f/libopenapi v0.15.0 // indirect
|
||||
github.com/perimeterx/marshmallow v1.1.5 // indirect
|
||||
github.com/posener/complete v1.2.3 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/shopspring/decimal v1.3.1 // indirect
|
||||
github.com/speakeasy-api/openapi-overlay v0.9.0 // indirect
|
||||
github.com/speakeasy-api/jsonpath v0.6.0 // indirect
|
||||
github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect
|
||||
github.com/spf13/cast v1.5.1 // indirect
|
||||
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
|
||||
@@ -97,20 +101,20 @@ 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.3 // indirect
|
||||
go.abhg.dev/goldmark/frontmatter v0.2.0 // indirect
|
||||
golang.org/x/crypto v0.28.0 // indirect
|
||||
golang.org/x/crypto v0.40.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 // indirect
|
||||
golang.org/x/mod v0.21.0 // indirect
|
||||
golang.org/x/net v0.30.0 // indirect
|
||||
golang.org/x/sync v0.8.0 // indirect
|
||||
golang.org/x/sys v0.26.0 // indirect
|
||||
golang.org/x/text v0.19.0 // indirect
|
||||
golang.org/x/tools v0.22.0 // indirect
|
||||
golang.org/x/mod v0.25.0 // indirect
|
||||
golang.org/x/net v0.42.0 // indirect
|
||||
golang.org/x/sync v0.16.0 // indirect
|
||||
golang.org/x/sys v0.34.0 // indirect
|
||||
golang.org/x/text v0.27.0 // indirect
|
||||
golang.org/x/tools v0.34.0 // indirect
|
||||
google.golang.org/appengine v1.6.8 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 // indirect
|
||||
google.golang.org/grpc v1.67.1 // indirect
|
||||
google.golang.org/protobuf v1.35.1 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250728155136-f173205681a0 // indirect
|
||||
google.golang.org/grpc v1.74.2 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
@@ -11,10 +11,10 @@ github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0
|
||||
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
|
||||
github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
|
||||
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/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw=
|
||||
github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
||||
github.com/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=
|
||||
@@ -39,11 +39,11 @@ github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx2
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
|
||||
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
|
||||
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
|
||||
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||
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.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
|
||||
github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
|
||||
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=
|
||||
@@ -63,14 +63,18 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
|
||||
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
|
||||
github.com/getkin/kin-openapi v0.127.0 h1:Mghqi3Dhryf3F8vR370nN67pAERW+3a95vomb3MAREY=
|
||||
github.com/getkin/kin-openapi v0.127.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM=
|
||||
github.com/getkin/kin-openapi v0.132.0 h1:3ISeLMsQzcb5v26yeJrBcdTCEQTag36ZjaGk7MIRUwk=
|
||||
github.com/getkin/kin-openapi v0.132.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58=
|
||||
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.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM=
|
||||
github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
|
||||
github.com/go-git/go-git/v5 v5.14.0 h1:/MD3lCrGjCen5WfEAzKg00MJJffKhC8gzS80ycmCi60=
|
||||
github.com/go-git/go-git/v5 v5.14.0/go.mod h1:Z5Xhoia5PcWA3NF8vRLURn9E5FRhSl7dGj9ItW3Wk5k=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
|
||||
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
|
||||
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
|
||||
@@ -78,8 +82,8 @@ github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
|
||||
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
|
||||
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
@@ -97,14 +101,14 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
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=
|
||||
@@ -113,15 +117,15 @@ github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuD
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||
github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 h1:1/D3zfFHttUKaCaGKZ/dR2roBXv0vKbSCnssIldfQdI=
|
||||
github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320/go.mod h1:EiZBMaudVLy8fmjf9Npq1dq9RalhveqZG5w/yz3mHWs=
|
||||
github.com/hashicorp/go-cty v1.5.0 h1:EkQ/v+dDNUqnuVpmS5fPqyY71NXVgT5gf32+57xY8g0=
|
||||
github.com/hashicorp/go-cty v1.5.0/go.mod h1:lFUCG5kd8exDobgSfyj4ONE/dc822kiYMguVKdHGMLM=
|
||||
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
|
||||
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/hashicorp/go-plugin v1.6.2 h1:zdGAEd0V1lCaU0u+MxWQhtSDQmahpkwOun8U8EiRVog=
|
||||
github.com/hashicorp/go-plugin v1.6.2/go.mod h1:CkgLQ5CZqNmdL9U9JzM532t8ZiYQ35+pj3b1FD37R0Q=
|
||||
github.com/hashicorp/go-plugin v1.6.3 h1:xgHB+ZUSYeuJi96WtxEjzi23uh7YQpznjGh0U0UUrwg=
|
||||
github.com/hashicorp/go-plugin v1.6.3/go.mod h1:MRobyh+Wc/nYy1V4KAXUiYfzxoYhs7V1mlH1Z7iY2h0=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
@@ -129,40 +133,40 @@ 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/hcl/v2 v2.21.0 h1:lve4q/o/2rqwYOgUg3y3V2YPyD1/zkCLGjIV74Jit14=
|
||||
github.com/hashicorp/hcl/v2 v2.21.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA=
|
||||
github.com/hashicorp/hc-install v0.9.2 h1:v80EtNX4fCVHqzL9Lg/2xkp62bbvQMnvPQ0G+OmtO24=
|
||||
github.com/hashicorp/hc-install v0.9.2/go.mod h1:XUqBQNnuT4RsxoxiM9ZaUk0NX8hi2h+Lb6/c0OZnC/I=
|
||||
github.com/hashicorp/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.23.0 h1:MUiBM1s0CNlRFsCLJuM5wXZrzA3MnPYEsiXmzATMW/I=
|
||||
github.com/hashicorp/terraform-exec v0.23.0/go.mod h1:mA+qnx1R8eePycfwKkCRk3Wy65mwInvlpAeOwmA7vlY=
|
||||
github.com/hashicorp/terraform-json v0.25.0 h1:rmNqc/CIfcWawGiwXmRuiXJKEiJu1ntGoxseG1hLhoQ=
|
||||
github.com/hashicorp/terraform-json v0.25.0/go.mod h1:sMKS8fiRDX4rVlR6EJUMudg1WcanxCMoWwTLkgZP/vc=
|
||||
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.0 h1:ox7rm1FN0dVZaJBUzkVVh10R1r3+FeMQWL0QopQ9d7o=
|
||||
github.com/hashicorp/terraform-plugin-docs v0.20.0/go.mod h1:A/+4SVMdAkQYtIBtaxV0H7AU862TxVZk/hhKaMDQB6Y=
|
||||
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-framework-timeouts v0.4.1 h1:gm5b1kHgFFhaKFhm4h2TgvMUlNzFAtUqlcOWnWPm+9E=
|
||||
github.com/hashicorp/terraform-plugin-framework-timeouts v0.4.1/go.mod h1:MsjL1sQ9L7wGwzJ5RjcI6FzEMdyoBnw+XK8ZnOvQOLY=
|
||||
github.com/hashicorp/terraform-plugin-framework-validators v0.15.0 h1:RXMmu7JgpFjnI1a5QjMCBb11usrW2OtAG+iOTIj5c9Y=
|
||||
github.com/hashicorp/terraform-plugin-framework-validators v0.15.0/go.mod h1:Bh89/hNmqsEWug4/XWKYBwtnw3tbz5BAy1L1OgvbIaY=
|
||||
github.com/hashicorp/terraform-plugin-go v0.25.0 h1:oi13cx7xXA6QciMcpcFi/rwA974rdTxjqEhXJjbAyks=
|
||||
github.com/hashicorp/terraform-plugin-go v0.25.0/go.mod h1:+SYagMYadJP86Kvn+TGeV+ofr/R3g4/If0O5sO96MVw=
|
||||
github.com/hashicorp/terraform-plugin-docs v0.22.0 h1:fwIDStbFel1PPNkM+mDPnpB4efHZBdGoMz/zt5FbTDw=
|
||||
github.com/hashicorp/terraform-plugin-docs v0.22.0/go.mod h1:55DJVyZ7BNK4t/lANcQ1YpemRuS6KsvIO1BbGA+xzGE=
|
||||
github.com/hashicorp/terraform-plugin-framework v1.15.1 h1:2mKDkwb8rlx/tvJTlIcpw0ykcmvdWv+4gY3SIgk8Pq8=
|
||||
github.com/hashicorp/terraform-plugin-framework v1.15.1/go.mod h1:hxrNI/GY32KPISpWqlCoTLM9JZsGH3CyYlir09bD/fI=
|
||||
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.18.0 h1:OQnlOt98ua//rCw+QhBbSqfW3QbwtVrcdWeQN5gI3Hw=
|
||||
github.com/hashicorp/terraform-plugin-framework-validators v0.18.0/go.mod h1:lZvZvagw5hsJwuY7mAY6KUz45/U6fiDR0CzQAwWD0CA=
|
||||
github.com/hashicorp/terraform-plugin-go v0.28.0 h1:zJmu2UDwhVN0J+J20RE5huiF3XXlTYVIleaevHZgKPA=
|
||||
github.com/hashicorp/terraform-plugin-go v0.28.0/go.mod h1:FDa2Bb3uumkTGSkTFpWSOwWJDwA7bf3vdP3ltLDTH6o=
|
||||
github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0=
|
||||
github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow=
|
||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0 h1:kJiWGx2kiQVo97Y5IOGR4EMcZ8DtMswHhUuFibsCQQE=
|
||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0/go.mod h1:sl/UoabMc37HA6ICVMmGO+/0wofkVIRxf+BMb/dnoIg=
|
||||
github.com/hashicorp/terraform-plugin-testing v1.10.0 h1:2+tmRNhvnfE4Bs8rB6v58S/VpqzGC6RCh9Y8ujdn+aw=
|
||||
github.com/hashicorp/terraform-plugin-testing v1.10.0/go.mod h1:iWRW3+loP33WMch2P/TEyCxxct/ZEcCGMquSLSCVsrc=
|
||||
github.com/hashicorp/terraform-registry-address v0.2.3 h1:2TAiKJ1A3MAkZlH1YI/aTVcLZRu7JseiXNRHbOAyoTI=
|
||||
github.com/hashicorp/terraform-registry-address v0.2.3/go.mod h1:lFHA76T8jfQteVfT7caREqguFrW3c4MFSPhZB7HHgUM=
|
||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.37.0 h1:NFPMacTrY/IdcIcnUB+7hsore1ZaRWU9cnB6jFoBnIM=
|
||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.37.0/go.mod h1:QYmYnLfsosrxjCnGY1p9c7Zj6n9thnEE+7RObeYs3fA=
|
||||
github.com/hashicorp/terraform-plugin-testing v1.13.3 h1:QLi/khB8Z0a5L54AfPrHukFpnwsGL8cwwswj4RZduCo=
|
||||
github.com/hashicorp/terraform-plugin-testing v1.13.3/go.mod h1:WHQ9FDdiLoneey2/QHpGM/6SAYf4A7AZazVg7230pLE=
|
||||
github.com/hashicorp/terraform-registry-address v0.3.0 h1:HMpK3nqaGFPS9VmgRXrJL/dzHNdheGVKk5k7VlFxzCo=
|
||||
github.com/hashicorp/terraform-registry-address v0.3.0/go.mod h1:jRGCMiLaY9zii3GLC7hqpSnwhfnCN5yzvY0hh4iCGbM=
|
||||
github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S52uzrw4x0jKQ=
|
||||
github.com/hashicorp/terraform-svchost v0.1.1/go.mod h1:mNsjQfZyf/Jhz35v6/0LWcv26+X7JPS+buii2c9/ctc=
|
||||
github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8=
|
||||
@@ -175,8 +179,6 @@ github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:
|
||||
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
|
||||
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
|
||||
github.com/invopop/yaml v0.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso=
|
||||
github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||
github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c=
|
||||
@@ -197,11 +199,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=
|
||||
@@ -223,12 +224,16 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwd
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/oapi-codegen/oapi-codegen/v2 v2.4.1 h1:ykgG34472DWey7TSjd8vIfNykXgjOgYJZoQbKfEeY/Q=
|
||||
github.com/oapi-codegen/oapi-codegen/v2 v2.4.1/go.mod h1:N5+lY1tiTDV3V1BeHtOxeWXHoPVeApvsvjJqegfoaz8=
|
||||
github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro=
|
||||
github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg=
|
||||
github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA=
|
||||
github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU=
|
||||
github.com/oapi-codegen/oapi-codegen/v2 v2.5.0 h1:iJvF8SdB/3/+eGOXEpsWkD8FQAHj6mqkb6Fnsoc8MFU=
|
||||
github.com/oapi-codegen/oapi-codegen/v2 v2.5.0/go.mod h1:fwlMxUEMuQK5ih9aymrxKPQqNm2n8bdLk1ppjH+lr9w=
|
||||
github.com/oapi-codegen/runtime v1.1.2 h1:P2+CubHq8fO4Q6fV1tqDBZHCwpVpvPg7oKiYzQgXIyI=
|
||||
github.com/oapi-codegen/runtime v1.1.2/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg=
|
||||
github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY=
|
||||
github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw=
|
||||
github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c=
|
||||
github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o=
|
||||
github.com/oklog/run v1.2.0 h1:O8x3yXwah4A73hJdlrwo/2X6J62gE5qTMusH0dvz60E=
|
||||
github.com/oklog/run v1.2.0/go.mod h1:mgDbKRSwPhJfesJ4PntqFUbKQRZ50NgmZTSPlFA0YFk=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
@@ -246,8 +251,8 @@ github.com/pb33f/libopenapi v0.15.0 h1:AoBYIY3HXqDDF8O9kcudlqWaRFZZJmgtueE649oHz
|
||||
github.com/pb33f/libopenapi v0.15.0/go.mod h1:m+4Pwri31UvcnZjuP8M7TlbR906DXJmMvYsbis234xg=
|
||||
github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s=
|
||||
github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
|
||||
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
|
||||
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
|
||||
github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4=
|
||||
github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
@@ -256,18 +261,20 @@ github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSg
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
||||
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/speakeasy-api/openapi-overlay v0.9.0 h1:Wrz6NO02cNlLzx1fB093lBlYxSI54VRhy1aSutx0PQg=
|
||||
github.com/speakeasy-api/openapi-overlay v0.9.0/go.mod h1:f5FloQrHA7MsxYg9djzMD5h6dxrHjVVByWKh7an8TRc=
|
||||
github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8=
|
||||
github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY=
|
||||
github.com/speakeasy-api/jsonpath v0.6.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8=
|
||||
github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw=
|
||||
github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU=
|
||||
github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg=
|
||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=
|
||||
github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48=
|
||||
@@ -278,8 +285,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
||||
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
|
||||
@@ -308,25 +315,37 @@ github.com/yuin/goldmark v1.7.7 h1:5m9rrB1sW3JUMToKFQfb+FGt1U7r57IHu5GrYrG2nqU=
|
||||
github.com/yuin/goldmark v1.7.7/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
|
||||
github.com/yuin/goldmark-meta v1.1.0 h1:pWw+JLHGZe8Rk0EGsMVssiNb/AaPMHfSRszZeUeiOUc=
|
||||
github.com/yuin/goldmark-meta v1.1.0/go.mod h1:U4spWENafuA7Zyg+Lj5RqK/MF+ovMYtBvXi1lBb2VP0=
|
||||
github.com/zclconf/go-cty v1.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.3 h1:osr++gw2T61A8KVYHoQiFbFd1Lh3JOCXc/jFLJXKTxk=
|
||||
github.com/zclconf/go-cty v1.16.3/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=
|
||||
go.abhg.dev/goldmark/frontmatter v0.2.0/go.mod h1:XqrEkZuM57djk7zrlRUB02x8I5J0px76YjkOzhB4YlU=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
|
||||
go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
|
||||
go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
|
||||
go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
|
||||
go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
|
||||
go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
|
||||
go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
|
||||
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
|
||||
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
|
||||
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
|
||||
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
|
||||
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.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
|
||||
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
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=
|
||||
@@ -337,14 +356,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.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
|
||||
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
|
||||
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
|
||||
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
|
||||
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.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
|
||||
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
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=
|
||||
@@ -367,29 +386,27 @@ 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.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
|
||||
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
|
||||
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
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=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
|
||||
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
|
||||
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
|
||||
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
|
||||
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
|
||||
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -397,10 +414,10 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
|
||||
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 h1:zciRKQ4kBpFgpfC5QQCVtnnNAcLIqweL7plyZRQHVpI=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
|
||||
google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E=
|
||||
google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250728155136-f173205681a0 h1:MAKi5q709QWfnkkpNQ0M12hYJ1+e8qYVDyowc4U1XZM=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250728155136-f173205681a0/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4=
|
||||
google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
@@ -409,8 +426,8 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
|
||||
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
+190
-2144
File diff suppressed because it is too large
Load Diff
@@ -1,46 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
OPENAPI_FILE=$(dirname "$0")/openapi.json
|
||||
|
||||
# Fetch the latest OpenAPI spec
|
||||
curl https://api.binarylane.com.au/reference/openapi.json --output $OPENAPI_FILE
|
||||
|
||||
# Move the /v2 prefix to the base URL and remove it from the paths
|
||||
cat <<<$(jq '.servers[0].url = "https://api.binarylane.com.au/v2"' $OPENAPI_FILE) >$OPENAPI_FILE
|
||||
cat <<<$(jq '.paths |= with_entries(.key |= sub("/v2/"; "/"))' $OPENAPI_FILE) >$OPENAPI_FILE
|
||||
|
||||
# Terraform can't handle oneOf types, so we need to replace them with basic types
|
||||
cat <<<$(jq '.components.schemas.CreateServerRequest.properties.image |= del(.oneOf) + {type:"string"}' $OPENAPI_FILE) >$OPENAPI_FILE
|
||||
cat <<<$(jq '.components.schemas.CreateServerRequest.properties.ssh_keys.items |= del(.oneOf) + {type:"integer"}' $OPENAPI_FILE) >$OPENAPI_FILE
|
||||
cat <<<$(jq '.components.schemas.Rebuild.properties.image |= del(.oneOf) + {type:"string"}' $OPENAPI_FILE) >$OPENAPI_FILE
|
||||
cat <<<$(jq '.components.schemas.ImageOptions.properties.ssh_keys.items |= del(.oneOf) + {type:"integer"}' $OPENAPI_FILE) >$OPENAPI_FILE
|
||||
cat <<<$(jq '.components.schemas.ChangeImage.properties.image |= del(.oneOf) + {type:"string"}' $OPENAPI_FILE) >$OPENAPI_FILE
|
||||
cat <<<$(jq '.paths["/account/keys/{key_id}"].delete.parameters[0].schema |= del(.oneOf) + {type:"integer"}' $OPENAPI_FILE) >$OPENAPI_FILE
|
||||
cat <<<$(jq '.paths["/account/keys/{key_id}"].put.parameters[0].schema |= del(.oneOf) + {type:"integer"}' $OPENAPI_FILE) >$OPENAPI_FILE
|
||||
cat <<<$(jq '.paths["/account/keys/{key_id}"].get.parameters[0].schema |= del(.oneOf) + {type:"integer"}' $OPENAPI_FILE) >$OPENAPI_FILE
|
||||
cat <<<$(jq '.paths["/account/keys/{key_id}"].delete.parameters[0].schema |= del(.oneOf) + {type:"integer"}' $OPENAPI_FILE) >$OPENAPI_FILE
|
||||
cat <<<$(jq '.paths["/account/keys/{key_id}"].delete.parameters[0].schema |= del(.oneOf) + {type:"integer"}' $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
|
||||
|
||||
# Add x-oapi-codegen-extra-tags so structs can be reflected
|
||||
|
||||
## RouteEntryRequest
|
||||
cat <<<$(jq '.components.schemas.RouteEntryRequest.properties.destination += {"x-oapi-codegen-extra-tags": {"tfsdk": "destination"}}' $OPENAPI_FILE) >$OPENAPI_FILE
|
||||
cat <<<$(jq '.components.schemas.RouteEntryRequest.properties.description += {"x-oapi-codegen-extra-tags": {"tfsdk": "description"}}' $OPENAPI_FILE) >$OPENAPI_FILE
|
||||
cat <<<$(jq '.components.schemas.RouteEntryRequest.properties.router += {"x-oapi-codegen-extra-tags": {"tfsdk": "router"}}' $OPENAPI_FILE) >$OPENAPI_FILE
|
||||
|
||||
## AdvancedFirewallRule
|
||||
cat <<<$(jq '.components.schemas.AdvancedFirewallRule.properties.description += {"x-oapi-codegen-extra-tags": {"tfsdk": "description"}}' $OPENAPI_FILE) >$OPENAPI_FILE
|
||||
cat <<<$(jq '.components.schemas.AdvancedFirewallRule.properties.protocol += {"x-oapi-codegen-extra-tags": {"tfsdk": "protocol"}}' $OPENAPI_FILE) >$OPENAPI_FILE
|
||||
cat <<<$(jq '.components.schemas.AdvancedFirewallRule.properties.action += {"x-oapi-codegen-extra-tags": {"tfsdk": "action"}}' $OPENAPI_FILE) >$OPENAPI_FILE
|
||||
cat <<<$(jq '.components.schemas.AdvancedFirewallRule.properties.destination_addresses += {"x-oapi-codegen-extra-tags": {"tfsdk": "destination_addresses"}}' $OPENAPI_FILE) >$OPENAPI_FILE
|
||||
cat <<<$(jq '.components.schemas.AdvancedFirewallRule.properties.destination_ports += {"x-oapi-codegen-extra-tags": {"tfsdk": "destination_ports"}}' $OPENAPI_FILE) >$OPENAPI_FILE
|
||||
cat <<<$(jq '.components.schemas.AdvancedFirewallRule.properties.source_addresses += {"x-oapi-codegen-extra-tags": {"tfsdk": "source_addresses"}}' $OPENAPI_FILE) >$OPENAPI_FILE
|
||||
|
||||
## Load Balancer
|
||||
cat <<<$(jq '.components.schemas.CreateLoadBalancerRequest.properties.forwarding_rules += {"x-oapi-codegen-extra-tags": {"tfsdk": "forwarding_rules"}}' $OPENAPI_FILE) >$OPENAPI_FILE
|
||||
cat <<<$(jq '.components.schemas.ForwardingRule.properties.entry_protocol += {"x-oapi-codegen-extra-tags": {"tfsdk": "entry_protocol"}}' $OPENAPI_FILE) >$OPENAPI_FILE
|
||||
cat <<<$(jq '.components.schemas.LoadBalancer.properties.health_check += {"x-oapi-codegen-extra-tags": {"tfsdk": "health_check"}}' $OPENAPI_FILE) >$OPENAPI_FILE
|
||||
cat <<<$(jq '.components.schemas.HealthCheckProtocol |= del(.enum)' $OPENAPI_FILE) >$OPENAPI_FILE
|
||||
+414
-492
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,776 @@
|
||||
// Code generated by terraform-plugin-framework-generator DO NOT EDIT.
|
||||
|
||||
package data_sources
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/hashicorp/terraform-plugin-framework/attr"
|
||||
"github.com/hashicorp/terraform-plugin-framework/diag"
|
||||
"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/datasource/schema"
|
||||
)
|
||||
|
||||
func RegionsDataSourceSchema(ctx context.Context) schema.Schema {
|
||||
return schema.Schema{
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"regions": schema.ListNestedAttribute{
|
||||
NestedObject: schema.NestedAttributeObject{
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"available": schema.BoolAttribute{
|
||||
Computed: true,
|
||||
Description: "Whether this region is available for the allocation of new resources.",
|
||||
MarkdownDescription: "Whether this region is available for the allocation of new resources.",
|
||||
},
|
||||
"features": schema.ListAttribute{
|
||||
ElementType: types.StringType,
|
||||
Computed: true,
|
||||
Description: "A list of features available for resources in this region.",
|
||||
MarkdownDescription: "A list of features available for resources in this region.",
|
||||
},
|
||||
"name": schema.StringAttribute{
|
||||
Computed: true,
|
||||
Description: "The name of this region.",
|
||||
MarkdownDescription: "The name of this region.",
|
||||
},
|
||||
"name_servers": schema.ListAttribute{
|
||||
ElementType: types.StringType,
|
||||
Computed: true,
|
||||
Description: "A list of nameservers available for resources in this region.",
|
||||
MarkdownDescription: "A list of nameservers available for resources in this region.",
|
||||
},
|
||||
"sizes": schema.ListAttribute{
|
||||
ElementType: types.StringType,
|
||||
Computed: true,
|
||||
Description: "The slugs of the sizes available in this region.",
|
||||
MarkdownDescription: "The slugs of the sizes available in this region.",
|
||||
},
|
||||
"slug": schema.StringAttribute{
|
||||
Computed: true,
|
||||
Description: "The unique slug for this region.",
|
||||
MarkdownDescription: "The unique slug for this region.",
|
||||
},
|
||||
},
|
||||
CustomType: RegionsType{
|
||||
ObjectType: types.ObjectType{
|
||||
AttrTypes: RegionsValue{}.AttributeTypes(ctx),
|
||||
},
|
||||
},
|
||||
},
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type RegionsModel struct {
|
||||
Regions types.List `tfsdk:"regions"`
|
||||
}
|
||||
|
||||
var _ basetypes.ObjectTypable = RegionsType{}
|
||||
|
||||
type RegionsType struct {
|
||||
basetypes.ObjectType
|
||||
}
|
||||
|
||||
func (t RegionsType) Equal(o attr.Type) bool {
|
||||
other, ok := o.(RegionsType)
|
||||
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
return t.ObjectType.Equal(other.ObjectType)
|
||||
}
|
||||
|
||||
func (t RegionsType) String() string {
|
||||
return "RegionsType"
|
||||
}
|
||||
|
||||
func (t RegionsType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) {
|
||||
var diags diag.Diagnostics
|
||||
|
||||
attributes := in.Attributes()
|
||||
|
||||
availableAttribute, ok := attributes["available"]
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Missing",
|
||||
`available is missing from object`)
|
||||
|
||||
return nil, diags
|
||||
}
|
||||
|
||||
availableVal, ok := availableAttribute.(basetypes.BoolValue)
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Wrong Type",
|
||||
fmt.Sprintf(`available expected to be basetypes.BoolValue, was: %T`, availableAttribute))
|
||||
}
|
||||
|
||||
featuresAttribute, ok := attributes["features"]
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Missing",
|
||||
`features is missing from object`)
|
||||
|
||||
return nil, diags
|
||||
}
|
||||
|
||||
featuresVal, ok := featuresAttribute.(basetypes.ListValue)
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Wrong Type",
|
||||
fmt.Sprintf(`features expected to be basetypes.ListValue, was: %T`, featuresAttribute))
|
||||
}
|
||||
|
||||
nameAttribute, ok := attributes["name"]
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Missing",
|
||||
`name is missing from object`)
|
||||
|
||||
return nil, diags
|
||||
}
|
||||
|
||||
nameVal, ok := nameAttribute.(basetypes.StringValue)
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Wrong Type",
|
||||
fmt.Sprintf(`name expected to be basetypes.StringValue, was: %T`, nameAttribute))
|
||||
}
|
||||
|
||||
nameServersAttribute, ok := attributes["name_servers"]
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Missing",
|
||||
`name_servers is missing from object`)
|
||||
|
||||
return nil, diags
|
||||
}
|
||||
|
||||
nameServersVal, ok := nameServersAttribute.(basetypes.ListValue)
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Wrong Type",
|
||||
fmt.Sprintf(`name_servers expected to be basetypes.ListValue, was: %T`, nameServersAttribute))
|
||||
}
|
||||
|
||||
sizesAttribute, ok := attributes["sizes"]
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Missing",
|
||||
`sizes is missing from object`)
|
||||
|
||||
return nil, diags
|
||||
}
|
||||
|
||||
sizesVal, ok := sizesAttribute.(basetypes.ListValue)
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Wrong Type",
|
||||
fmt.Sprintf(`sizes expected to be basetypes.ListValue, was: %T`, sizesAttribute))
|
||||
}
|
||||
|
||||
slugAttribute, ok := attributes["slug"]
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Missing",
|
||||
`slug is missing from object`)
|
||||
|
||||
return nil, diags
|
||||
}
|
||||
|
||||
slugVal, ok := slugAttribute.(basetypes.StringValue)
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Wrong Type",
|
||||
fmt.Sprintf(`slug expected to be basetypes.StringValue, was: %T`, slugAttribute))
|
||||
}
|
||||
|
||||
if diags.HasError() {
|
||||
return nil, diags
|
||||
}
|
||||
|
||||
return RegionsValue{
|
||||
Available: availableVal,
|
||||
Features: featuresVal,
|
||||
Name: nameVal,
|
||||
NameServers: nameServersVal,
|
||||
Sizes: sizesVal,
|
||||
Slug: slugVal,
|
||||
state: attr.ValueStateKnown,
|
||||
}, diags
|
||||
}
|
||||
|
||||
func NewRegionsValueNull() RegionsValue {
|
||||
return RegionsValue{
|
||||
state: attr.ValueStateNull,
|
||||
}
|
||||
}
|
||||
|
||||
func NewRegionsValueUnknown() RegionsValue {
|
||||
return RegionsValue{
|
||||
state: attr.ValueStateUnknown,
|
||||
}
|
||||
}
|
||||
|
||||
func NewRegionsValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (RegionsValue, 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 RegionsValue Attribute Value",
|
||||
"While creating a RegionsValue value, a missing attribute value was detected. "+
|
||||
"A RegionsValue 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("RegionsValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()),
|
||||
)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if !attributeType.Equal(attribute.Type(ctx)) {
|
||||
diags.AddError(
|
||||
"Invalid RegionsValue Attribute Type",
|
||||
"While creating a RegionsValue value, an invalid attribute value was detected. "+
|
||||
"A RegionsValue 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("RegionsValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+
|
||||
fmt.Sprintf("RegionsValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
for name := range attributes {
|
||||
_, ok := attributeTypes[name]
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Extra RegionsValue Attribute Value",
|
||||
"While creating a RegionsValue value, an extra attribute value was detected. "+
|
||||
"A RegionsValue 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 RegionsValue Attribute Name: %s", name),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if diags.HasError() {
|
||||
return NewRegionsValueUnknown(), diags
|
||||
}
|
||||
|
||||
availableAttribute, ok := attributes["available"]
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Missing",
|
||||
`available is missing from object`)
|
||||
|
||||
return NewRegionsValueUnknown(), diags
|
||||
}
|
||||
|
||||
availableVal, ok := availableAttribute.(basetypes.BoolValue)
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Wrong Type",
|
||||
fmt.Sprintf(`available expected to be basetypes.BoolValue, was: %T`, availableAttribute))
|
||||
}
|
||||
|
||||
featuresAttribute, ok := attributes["features"]
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Missing",
|
||||
`features is missing from object`)
|
||||
|
||||
return NewRegionsValueUnknown(), diags
|
||||
}
|
||||
|
||||
featuresVal, ok := featuresAttribute.(basetypes.ListValue)
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Wrong Type",
|
||||
fmt.Sprintf(`features expected to be basetypes.ListValue, was: %T`, featuresAttribute))
|
||||
}
|
||||
|
||||
nameAttribute, ok := attributes["name"]
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Missing",
|
||||
`name is missing from object`)
|
||||
|
||||
return NewRegionsValueUnknown(), diags
|
||||
}
|
||||
|
||||
nameVal, ok := nameAttribute.(basetypes.StringValue)
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Wrong Type",
|
||||
fmt.Sprintf(`name expected to be basetypes.StringValue, was: %T`, nameAttribute))
|
||||
}
|
||||
|
||||
nameServersAttribute, ok := attributes["name_servers"]
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Missing",
|
||||
`name_servers is missing from object`)
|
||||
|
||||
return NewRegionsValueUnknown(), diags
|
||||
}
|
||||
|
||||
nameServersVal, ok := nameServersAttribute.(basetypes.ListValue)
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Wrong Type",
|
||||
fmt.Sprintf(`name_servers expected to be basetypes.ListValue, was: %T`, nameServersAttribute))
|
||||
}
|
||||
|
||||
sizesAttribute, ok := attributes["sizes"]
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Missing",
|
||||
`sizes is missing from object`)
|
||||
|
||||
return NewRegionsValueUnknown(), diags
|
||||
}
|
||||
|
||||
sizesVal, ok := sizesAttribute.(basetypes.ListValue)
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Wrong Type",
|
||||
fmt.Sprintf(`sizes expected to be basetypes.ListValue, was: %T`, sizesAttribute))
|
||||
}
|
||||
|
||||
slugAttribute, ok := attributes["slug"]
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Missing",
|
||||
`slug is missing from object`)
|
||||
|
||||
return NewRegionsValueUnknown(), diags
|
||||
}
|
||||
|
||||
slugVal, ok := slugAttribute.(basetypes.StringValue)
|
||||
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Attribute Wrong Type",
|
||||
fmt.Sprintf(`slug expected to be basetypes.StringValue, was: %T`, slugAttribute))
|
||||
}
|
||||
|
||||
if diags.HasError() {
|
||||
return NewRegionsValueUnknown(), diags
|
||||
}
|
||||
|
||||
return RegionsValue{
|
||||
Available: availableVal,
|
||||
Features: featuresVal,
|
||||
Name: nameVal,
|
||||
NameServers: nameServersVal,
|
||||
Sizes: sizesVal,
|
||||
Slug: slugVal,
|
||||
state: attr.ValueStateKnown,
|
||||
}, diags
|
||||
}
|
||||
|
||||
func NewRegionsValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) RegionsValue {
|
||||
object, diags := NewRegionsValue(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("NewRegionsValueMust received error(s): " + strings.Join(diagsStrings, "\n"))
|
||||
}
|
||||
|
||||
return object
|
||||
}
|
||||
|
||||
func (t RegionsType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) {
|
||||
if in.Type() == nil {
|
||||
return NewRegionsValueNull(), 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 NewRegionsValueUnknown(), nil
|
||||
}
|
||||
|
||||
if in.IsNull() {
|
||||
return NewRegionsValueNull(), 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 NewRegionsValueMust(RegionsValue{}.AttributeTypes(ctx), attributes), nil
|
||||
}
|
||||
|
||||
func (t RegionsType) ValueType(ctx context.Context) attr.Value {
|
||||
return RegionsValue{}
|
||||
}
|
||||
|
||||
var _ basetypes.ObjectValuable = RegionsValue{}
|
||||
|
||||
type RegionsValue struct {
|
||||
Available basetypes.BoolValue `tfsdk:"available"`
|
||||
Features basetypes.ListValue `tfsdk:"features"`
|
||||
Name basetypes.StringValue `tfsdk:"name"`
|
||||
NameServers basetypes.ListValue `tfsdk:"name_servers"`
|
||||
Sizes basetypes.ListValue `tfsdk:"sizes"`
|
||||
Slug basetypes.StringValue `tfsdk:"slug"`
|
||||
state attr.ValueState
|
||||
}
|
||||
|
||||
func (v RegionsValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) {
|
||||
attrTypes := make(map[string]tftypes.Type, 6)
|
||||
|
||||
var val tftypes.Value
|
||||
var err error
|
||||
|
||||
attrTypes["available"] = basetypes.BoolType{}.TerraformType(ctx)
|
||||
attrTypes["features"] = basetypes.ListType{
|
||||
ElemType: types.StringType,
|
||||
}.TerraformType(ctx)
|
||||
attrTypes["name"] = basetypes.StringType{}.TerraformType(ctx)
|
||||
attrTypes["name_servers"] = basetypes.ListType{
|
||||
ElemType: types.StringType,
|
||||
}.TerraformType(ctx)
|
||||
attrTypes["sizes"] = basetypes.ListType{
|
||||
ElemType: types.StringType,
|
||||
}.TerraformType(ctx)
|
||||
attrTypes["slug"] = basetypes.StringType{}.TerraformType(ctx)
|
||||
|
||||
objectType := tftypes.Object{AttributeTypes: attrTypes}
|
||||
|
||||
switch v.state {
|
||||
case attr.ValueStateKnown:
|
||||
vals := make(map[string]tftypes.Value, 6)
|
||||
|
||||
val, err = v.Available.ToTerraformValue(ctx)
|
||||
|
||||
if err != nil {
|
||||
return tftypes.NewValue(objectType, tftypes.UnknownValue), err
|
||||
}
|
||||
|
||||
vals["available"] = val
|
||||
|
||||
val, err = v.Features.ToTerraformValue(ctx)
|
||||
|
||||
if err != nil {
|
||||
return tftypes.NewValue(objectType, tftypes.UnknownValue), err
|
||||
}
|
||||
|
||||
vals["features"] = val
|
||||
|
||||
val, err = v.Name.ToTerraformValue(ctx)
|
||||
|
||||
if err != nil {
|
||||
return tftypes.NewValue(objectType, tftypes.UnknownValue), err
|
||||
}
|
||||
|
||||
vals["name"] = val
|
||||
|
||||
val, err = v.NameServers.ToTerraformValue(ctx)
|
||||
|
||||
if err != nil {
|
||||
return tftypes.NewValue(objectType, tftypes.UnknownValue), err
|
||||
}
|
||||
|
||||
vals["name_servers"] = val
|
||||
|
||||
val, err = v.Sizes.ToTerraformValue(ctx)
|
||||
|
||||
if err != nil {
|
||||
return tftypes.NewValue(objectType, tftypes.UnknownValue), err
|
||||
}
|
||||
|
||||
vals["sizes"] = val
|
||||
|
||||
val, err = v.Slug.ToTerraformValue(ctx)
|
||||
|
||||
if err != nil {
|
||||
return tftypes.NewValue(objectType, tftypes.UnknownValue), err
|
||||
}
|
||||
|
||||
vals["slug"] = 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 RegionsValue) IsNull() bool {
|
||||
return v.state == attr.ValueStateNull
|
||||
}
|
||||
|
||||
func (v RegionsValue) IsUnknown() bool {
|
||||
return v.state == attr.ValueStateUnknown
|
||||
}
|
||||
|
||||
func (v RegionsValue) String() string {
|
||||
return "RegionsValue"
|
||||
}
|
||||
|
||||
func (v RegionsValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) {
|
||||
var diags diag.Diagnostics
|
||||
|
||||
var featuresVal basetypes.ListValue
|
||||
switch {
|
||||
case v.Features.IsUnknown():
|
||||
featuresVal = types.ListUnknown(types.StringType)
|
||||
case v.Features.IsNull():
|
||||
featuresVal = types.ListNull(types.StringType)
|
||||
default:
|
||||
var d diag.Diagnostics
|
||||
featuresVal, d = types.ListValue(types.StringType, v.Features.Elements())
|
||||
diags.Append(d...)
|
||||
}
|
||||
|
||||
if diags.HasError() {
|
||||
return types.ObjectUnknown(map[string]attr.Type{
|
||||
"available": basetypes.BoolType{},
|
||||
"features": basetypes.ListType{
|
||||
ElemType: types.StringType,
|
||||
},
|
||||
"name": basetypes.StringType{},
|
||||
"name_servers": basetypes.ListType{
|
||||
ElemType: types.StringType,
|
||||
},
|
||||
"sizes": basetypes.ListType{
|
||||
ElemType: types.StringType,
|
||||
},
|
||||
"slug": basetypes.StringType{},
|
||||
}), diags
|
||||
}
|
||||
|
||||
var nameServersVal basetypes.ListValue
|
||||
switch {
|
||||
case v.NameServers.IsUnknown():
|
||||
nameServersVal = types.ListUnknown(types.StringType)
|
||||
case v.NameServers.IsNull():
|
||||
nameServersVal = types.ListNull(types.StringType)
|
||||
default:
|
||||
var d diag.Diagnostics
|
||||
nameServersVal, d = types.ListValue(types.StringType, v.NameServers.Elements())
|
||||
diags.Append(d...)
|
||||
}
|
||||
|
||||
if diags.HasError() {
|
||||
return types.ObjectUnknown(map[string]attr.Type{
|
||||
"available": basetypes.BoolType{},
|
||||
"features": basetypes.ListType{
|
||||
ElemType: types.StringType,
|
||||
},
|
||||
"name": basetypes.StringType{},
|
||||
"name_servers": basetypes.ListType{
|
||||
ElemType: types.StringType,
|
||||
},
|
||||
"sizes": basetypes.ListType{
|
||||
ElemType: types.StringType,
|
||||
},
|
||||
"slug": basetypes.StringType{},
|
||||
}), diags
|
||||
}
|
||||
|
||||
var sizesVal basetypes.ListValue
|
||||
switch {
|
||||
case v.Sizes.IsUnknown():
|
||||
sizesVal = types.ListUnknown(types.StringType)
|
||||
case v.Sizes.IsNull():
|
||||
sizesVal = types.ListNull(types.StringType)
|
||||
default:
|
||||
var d diag.Diagnostics
|
||||
sizesVal, d = types.ListValue(types.StringType, v.Sizes.Elements())
|
||||
diags.Append(d...)
|
||||
}
|
||||
|
||||
if diags.HasError() {
|
||||
return types.ObjectUnknown(map[string]attr.Type{
|
||||
"available": basetypes.BoolType{},
|
||||
"features": basetypes.ListType{
|
||||
ElemType: types.StringType,
|
||||
},
|
||||
"name": basetypes.StringType{},
|
||||
"name_servers": basetypes.ListType{
|
||||
ElemType: types.StringType,
|
||||
},
|
||||
"sizes": basetypes.ListType{
|
||||
ElemType: types.StringType,
|
||||
},
|
||||
"slug": basetypes.StringType{},
|
||||
}), diags
|
||||
}
|
||||
|
||||
attributeTypes := map[string]attr.Type{
|
||||
"available": basetypes.BoolType{},
|
||||
"features": basetypes.ListType{
|
||||
ElemType: types.StringType,
|
||||
},
|
||||
"name": basetypes.StringType{},
|
||||
"name_servers": basetypes.ListType{
|
||||
ElemType: types.StringType,
|
||||
},
|
||||
"sizes": basetypes.ListType{
|
||||
ElemType: types.StringType,
|
||||
},
|
||||
"slug": basetypes.StringType{},
|
||||
}
|
||||
|
||||
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{
|
||||
"available": v.Available,
|
||||
"features": featuresVal,
|
||||
"name": v.Name,
|
||||
"name_servers": nameServersVal,
|
||||
"sizes": sizesVal,
|
||||
"slug": v.Slug,
|
||||
})
|
||||
|
||||
return objVal, diags
|
||||
}
|
||||
|
||||
func (v RegionsValue) Equal(o attr.Value) bool {
|
||||
other, ok := o.(RegionsValue)
|
||||
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
if v.state != other.state {
|
||||
return false
|
||||
}
|
||||
|
||||
if v.state != attr.ValueStateKnown {
|
||||
return true
|
||||
}
|
||||
|
||||
if !v.Available.Equal(other.Available) {
|
||||
return false
|
||||
}
|
||||
|
||||
if !v.Features.Equal(other.Features) {
|
||||
return false
|
||||
}
|
||||
|
||||
if !v.Name.Equal(other.Name) {
|
||||
return false
|
||||
}
|
||||
|
||||
if !v.NameServers.Equal(other.NameServers) {
|
||||
return false
|
||||
}
|
||||
|
||||
if !v.Sizes.Equal(other.Sizes) {
|
||||
return false
|
||||
}
|
||||
|
||||
if !v.Slug.Equal(other.Slug) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (v RegionsValue) Type(ctx context.Context) attr.Type {
|
||||
return RegionsType{
|
||||
basetypes.ObjectType{
|
||||
AttrTypes: v.AttributeTypes(ctx),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (v RegionsValue) AttributeTypes(ctx context.Context) map[string]attr.Type {
|
||||
return map[string]attr.Type{
|
||||
"available": basetypes.BoolType{},
|
||||
"features": basetypes.ListType{
|
||||
ElemType: types.StringType,
|
||||
},
|
||||
"name": basetypes.StringType{},
|
||||
"name_servers": basetypes.ListType{
|
||||
ElemType: types.StringType,
|
||||
},
|
||||
"sizes": basetypes.ListType{
|
||||
ElemType: types.StringType,
|
||||
},
|
||||
"slug": basetypes.StringType{},
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,104 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"terraform-provider-binarylane/internal/binarylane"
|
||||
"terraform-provider-binarylane/internal/data_sources"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework/datasource"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
)
|
||||
|
||||
var (
|
||||
_ datasource.DataSource = &imagesDataSource{}
|
||||
_ datasource.DataSourceWithConfigure = &imagesDataSource{}
|
||||
)
|
||||
|
||||
func NewImagesDataSource() datasource.DataSource {
|
||||
return &imagesDataSource{}
|
||||
}
|
||||
|
||||
type imagesDataSource struct {
|
||||
bc *BinarylaneClient
|
||||
}
|
||||
|
||||
type imagesDataSourceModel struct {
|
||||
data_sources.ImagesModel
|
||||
}
|
||||
|
||||
func (d *imagesDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
|
||||
resp.TypeName = req.ProviderTypeName + "_images"
|
||||
}
|
||||
|
||||
func (d *imagesDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
|
||||
if req.ProviderData == nil {
|
||||
return
|
||||
}
|
||||
|
||||
bc, ok := req.ProviderData.(BinarylaneClient)
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected Data Source Configure Type",
|
||||
fmt.Sprintf("Expected *BinarylaneClient, got: %T.", req.ProviderData))
|
||||
return
|
||||
}
|
||||
|
||||
d.bc = &bc
|
||||
}
|
||||
|
||||
func (d *imagesDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
|
||||
resp.Schema = data_sources.ImagesDataSourceSchema(ctx)
|
||||
}
|
||||
|
||||
func (d *imagesDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
|
||||
var data imagesDataSourceModel
|
||||
|
||||
// Read Terraform configuration data into the model
|
||||
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
// Read API call logic
|
||||
var page int32 = 1
|
||||
perPage := int32(200)
|
||||
var nextPage bool = true
|
||||
var imgResults []binarylane.Image
|
||||
|
||||
for nextPage {
|
||||
params := binarylane.GetImagesParams{
|
||||
Page: &page,
|
||||
PerPage: &perPage,
|
||||
Type: data.Type.ValueStringPointer(),
|
||||
}
|
||||
listResp, err := d.bc.client.GetImagesWithResponse(ctx, ¶ms)
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError("Error listing images", err.Error())
|
||||
return
|
||||
}
|
||||
if listResp.StatusCode() != http.StatusOK {
|
||||
resp.Diagnostics.AddError("Unexpected status code listing images", string(listResp.Body))
|
||||
return
|
||||
}
|
||||
imgResults = append(imgResults, *listResp.JSON200.Images...)
|
||||
|
||||
if listResp.JSON200.Links == nil || listResp.JSON200.Links.Pages == nil || listResp.JSON200.Links.Pages.Next == nil {
|
||||
nextPage = false
|
||||
break
|
||||
}
|
||||
page++
|
||||
}
|
||||
|
||||
images, diags := types.ListValueFrom(ctx, data.Images.ElementType(ctx), imgResults)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
data.Images = images
|
||||
|
||||
// Save data into Terraform state
|
||||
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
|
||||
)
|
||||
|
||||
func TestImagesDataSource(t *testing.T) {
|
||||
resource.ParallelTest(t, resource.TestCase{
|
||||
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
|
||||
Steps: []resource.TestStep{
|
||||
// Create and Read testing
|
||||
{
|
||||
Config: providerConfig + `
|
||||
data "binarylane_images" "test" {
|
||||
}
|
||||
`,
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
// Verify data source values
|
||||
resource.TestCheckResourceAttrWith("data.binarylane_images.test", "images.#", func(value string) error {
|
||||
count, err := strconv.Atoi(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if count < 1 {
|
||||
return fmt.Errorf("expected at least one image, got: %d", count)
|
||||
}
|
||||
return nil
|
||||
}),
|
||||
resource.TestCheckResourceAttrSet("data.binarylane_images.test", "images.0.id"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"terraform-provider-binarylane/internal/resources"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework/datasource"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -22,8 +23,9 @@ type loadBalancerDataSource struct {
|
||||
bc *BinarylaneClient
|
||||
}
|
||||
|
||||
type loadBalancerDataSourceModel struct {
|
||||
type loadBalancerDataModel struct {
|
||||
resources.LoadBalancerModel
|
||||
Ip types.String `tfsdk:"ip"`
|
||||
}
|
||||
|
||||
func (d *loadBalancerDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
|
||||
@@ -52,7 +54,7 @@ func (d *loadBalancerDataSource) Configure(
|
||||
|
||||
func (d *loadBalancerDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
|
||||
ds, err := convertResourceSchemaToDataSourceSchema(
|
||||
resources.LoadBalancerResourceSchema(ctx),
|
||||
loadBalancerSchema(ctx),
|
||||
AttributeConfig{
|
||||
RequiredAttributes: &[]string{"id"},
|
||||
},
|
||||
@@ -62,11 +64,12 @@ func (d *loadBalancerDataSource) Schema(ctx context.Context, req datasource.Sche
|
||||
return
|
||||
}
|
||||
resp.Schema = *ds
|
||||
// resp.Schema.Description = "TODO"
|
||||
resp.Schema.Description = "Retrieve details about a BinaryLane Load Balancer."
|
||||
resp.Schema.MarkdownDescription = resp.Schema.Description
|
||||
}
|
||||
|
||||
func (d *loadBalancerDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
|
||||
var data loadBalancerDataSourceModel
|
||||
var data loadBalancerDataModel
|
||||
|
||||
// Read Terraform prior state data into the model
|
||||
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
|
||||
@@ -93,7 +96,7 @@ func (d *loadBalancerDataSource) Read(ctx context.Context, req datasource.ReadRe
|
||||
return
|
||||
}
|
||||
|
||||
diags := SetLoadBalancerModelState(ctx, &data.LoadBalancerModel, lbResp.JSON200.LoadBalancer)
|
||||
diags := setLoadBalancerModelState(ctx, &data, lbResp.JSON200.LoadBalancer)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
|
||||
@@ -10,14 +10,17 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts"
|
||||
"github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
|
||||
"github.com/hashicorp/terraform-plugin-framework/attr"
|
||||
"github.com/hashicorp/terraform-plugin-framework/diag"
|
||||
"github.com/hashicorp/terraform-plugin-framework/path"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/listdefault"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
|
||||
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
"github.com/hashicorp/terraform-plugin-log/tflog"
|
||||
)
|
||||
@@ -37,7 +40,7 @@ type loadBalancerResource struct {
|
||||
}
|
||||
|
||||
type loadBalancerResourceModel struct {
|
||||
resources.LoadBalancerModel
|
||||
loadBalancerDataModel
|
||||
Timeouts timeouts.Value `tfsdk:"timeouts"`
|
||||
}
|
||||
|
||||
@@ -60,13 +63,15 @@ func (d *loadBalancerResource) Configure(_ context.Context, req resource.Configu
|
||||
d.bc = &bc
|
||||
}
|
||||
|
||||
func (r *loadBalancerResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
|
||||
resp.Schema = resources.LoadBalancerResourceSchema(ctx)
|
||||
// resp.Schema.Description = "TODO"
|
||||
func loadBalancerSchema(ctx context.Context) schema.Schema {
|
||||
s := resources.LoadBalancerResourceSchema(ctx)
|
||||
s.Description = "Provides a BinaryLane Load Balancer resource. This can be used to create, update, and delete load balancers."
|
||||
s.MarkdownDescription = s.Description +
|
||||
" See [the docs](https://support.binarylane.com.au/support/solutions/articles/1000025661-load-balancer) for more information."
|
||||
|
||||
// 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
|
||||
@@ -78,8 +83,8 @@ func (r *loadBalancerResource) Schema(ctx context.Context, req resource.SchemaRe
|
||||
},
|
||||
}
|
||||
|
||||
region := resp.Schema.Attributes["region"]
|
||||
resp.Schema.Attributes["region"] = &schema.StringAttribute{
|
||||
region := s.Attributes["region"]
|
||||
s.Attributes["region"] = schema.StringAttribute{
|
||||
Description: region.GetDescription(),
|
||||
MarkdownDescription: region.GetMarkdownDescription(),
|
||||
Optional: true,
|
||||
@@ -89,6 +94,49 @@ func (r *loadBalancerResource) Schema(ctx context.Context, req resource.SchemaRe
|
||||
},
|
||||
}
|
||||
|
||||
forwardingRules := s.Attributes["forwarding_rules"].(schema.ListNestedAttribute)
|
||||
s.Attributes["forwarding_rules"] = schema.ListNestedAttribute{
|
||||
NestedObject: forwardingRules.NestedObject,
|
||||
Description: forwardingRules.GetDescription(),
|
||||
MarkdownDescription: forwardingRules.GetMarkdownDescription(),
|
||||
Required: false,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
Default: listdefault.StaticValue(types.ListValueMust(
|
||||
types.ObjectType{
|
||||
AttrTypes: resources.ForwardingRulesValue{}.AttributeTypes(ctx),
|
||||
},
|
||||
[]attr.Value{
|
||||
types.ObjectValueMust(
|
||||
map[string]attr.Type{
|
||||
"entry_protocol": types.StringType,
|
||||
},
|
||||
map[string]attr.Value{
|
||||
"entry_protocol": types.StringValue("http"),
|
||||
},
|
||||
),
|
||||
},
|
||||
)),
|
||||
Validators: []validator.List{
|
||||
listvalidator.SizeAtLeast(1),
|
||||
},
|
||||
}
|
||||
|
||||
// Additional attributes
|
||||
s.Attributes["ip"] = schema.StringAttribute{
|
||||
Description: "The IPv4 address of the load balancer.",
|
||||
MarkdownDescription: "The IPv4 address of the load balancer.",
|
||||
Required: false,
|
||||
Optional: false,
|
||||
Computed: true,
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func (r *loadBalancerResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
|
||||
resp.Schema = loadBalancerSchema(ctx)
|
||||
|
||||
resp.Schema.Attributes["timeouts"] =
|
||||
timeouts.Attributes(ctx, timeouts.Opts{
|
||||
Create: true,
|
||||
@@ -106,7 +154,7 @@ func (r *loadBalancerResource) Create(ctx context.Context, req resource.CreateRe
|
||||
}
|
||||
|
||||
// Create API call logic
|
||||
forwardingRules := []binarylane.ForwardingRule{}
|
||||
forwardingRules := []binarylane.ForwardingRuleRequest{}
|
||||
diags := data.LoadBalancerModel.ForwardingRules.ElementsAs(ctx, &forwardingRules, false)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
@@ -127,7 +175,7 @@ func (r *loadBalancerResource) Create(ctx context.Context, req resource.CreateRe
|
||||
}
|
||||
|
||||
if data.HealthCheck.Path.ValueStringPointer() != nil || data.HealthCheck.Protocol.ValueStringPointer() != nil {
|
||||
body.HealthCheck = &binarylane.HealthCheck{
|
||||
body.HealthCheck = &binarylane.HealthCheckRequest{
|
||||
Path: data.HealthCheck.Path.ValueStringPointer(),
|
||||
Protocol: data.HealthCheck.Protocol.ValueStringPointer(),
|
||||
}
|
||||
@@ -152,7 +200,7 @@ func (r *loadBalancerResource) Create(ctx context.Context, req resource.CreateRe
|
||||
return
|
||||
}
|
||||
|
||||
diags = SetLoadBalancerModelState(ctx, &data.LoadBalancerModel, lbResp.JSON200.LoadBalancer)
|
||||
diags = setLoadBalancerModelState(ctx, &data.loadBalancerDataModel, lbResp.JSON200.LoadBalancer)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
@@ -237,6 +285,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",
|
||||
@@ -245,7 +299,7 @@ func (r *loadBalancerResource) Read(ctx context.Context, req resource.ReadReques
|
||||
return
|
||||
}
|
||||
|
||||
diags := SetLoadBalancerModelState(ctx, &data.LoadBalancerModel, lbResp.JSON200.LoadBalancer)
|
||||
diags := setLoadBalancerModelState(ctx, &data.loadBalancerDataModel, lbResp.JSON200.LoadBalancer)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
@@ -266,7 +320,7 @@ func (r *loadBalancerResource) Update(ctx context.Context, req resource.UpdateRe
|
||||
}
|
||||
|
||||
// Update API call logic
|
||||
forwardingRules := &[]binarylane.ForwardingRule{}
|
||||
forwardingRules := &[]binarylane.ForwardingRuleRequest{}
|
||||
diags := data.LoadBalancerModel.ForwardingRules.ElementsAs(ctx, forwardingRules, true)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
@@ -285,7 +339,7 @@ func (r *loadBalancerResource) Update(ctx context.Context, req resource.UpdateRe
|
||||
body := binarylane.UpdateLoadBalancerRequest{
|
||||
Name: data.Name.ValueString(),
|
||||
ForwardingRules: forwardingRules,
|
||||
HealthCheck: &binarylane.HealthCheck{
|
||||
HealthCheck: &binarylane.HealthCheckRequest{
|
||||
Path: data.HealthCheck.Path.ValueStringPointer(),
|
||||
Protocol: data.HealthCheck.Protocol.ValueStringPointer(),
|
||||
},
|
||||
@@ -309,7 +363,7 @@ func (r *loadBalancerResource) Update(ctx context.Context, req resource.UpdateRe
|
||||
return
|
||||
}
|
||||
|
||||
diags = SetLoadBalancerModelState(ctx, &data.LoadBalancerModel, lbResp.JSON200.LoadBalancer)
|
||||
diags = setLoadBalancerModelState(ctx, &data.loadBalancerDataModel, lbResp.JSON200.LoadBalancer)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
@@ -388,7 +442,7 @@ func (r *loadBalancerResource) ImportState(
|
||||
|
||||
loadBalancers := *lbResp.JSON200.LoadBalancers
|
||||
for _, lb := range loadBalancers {
|
||||
if *lb.Name == req.ID {
|
||||
if lb.Name == req.ID {
|
||||
loadBalancer = lb
|
||||
nextPage = false
|
||||
break
|
||||
@@ -402,23 +456,16 @@ func (r *loadBalancerResource) ImportState(
|
||||
page++
|
||||
}
|
||||
|
||||
if loadBalancer.Id == nil {
|
||||
resp.Diagnostics.AddError(
|
||||
"Could not find load balancer by name",
|
||||
fmt.Sprintf("Error finding load balancer: name=%s", req.ID),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
diags := resp.State.SetAttribute(ctx, path.Root("id"), *loadBalancer.Id)
|
||||
diags := resp.State.SetAttribute(ctx, path.Root("id"), loadBalancer.Id)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
}
|
||||
|
||||
func SetLoadBalancerModelState(ctx context.Context, data *resources.LoadBalancerModel, lb *binarylane.LoadBalancer) diag.Diagnostics {
|
||||
func setLoadBalancerModelState(ctx context.Context, data *loadBalancerDataModel, lb *binarylane.LoadBalancer) diag.Diagnostics {
|
||||
var diags, diag diag.Diagnostics
|
||||
|
||||
data.Id = types.Int64Value(*lb.Id)
|
||||
data.Name = types.StringValue(*lb.Name)
|
||||
data.Id = types.Int64Value(lb.Id)
|
||||
data.Name = types.StringValue(lb.Name)
|
||||
data.Ip = types.StringValue(lb.Ip)
|
||||
|
||||
if lb.Region == nil {
|
||||
data.Region = types.StringNull()
|
||||
@@ -428,18 +475,14 @@ func SetLoadBalancerModelState(ctx context.Context, data *resources.LoadBalancer
|
||||
|
||||
data.ServerIds, diags = types.ListValueFrom(ctx, types.Int64Type, lb.ServerIds)
|
||||
|
||||
if lb.HealthCheck == nil {
|
||||
data.HealthCheck = resources.NewHealthCheckValueNull()
|
||||
} else {
|
||||
data.HealthCheck, diag = resources.NewHealthCheckValue(
|
||||
resources.HealthCheckValue{}.AttributeTypes(ctx),
|
||||
map[string]attr.Value{
|
||||
"path": types.StringValue(*lb.HealthCheck.Path),
|
||||
"protocol": types.StringValue(*lb.HealthCheck.Protocol),
|
||||
},
|
||||
)
|
||||
diags.Append(diag...)
|
||||
}
|
||||
data.HealthCheck, diag = resources.NewHealthCheckValue(
|
||||
resources.HealthCheckValue{}.AttributeTypes(ctx),
|
||||
map[string]attr.Value{
|
||||
"path": types.StringValue(lb.HealthCheck.Path),
|
||||
"protocol": types.StringValue(lb.HealthCheck.Protocol),
|
||||
},
|
||||
)
|
||||
diags.Append(diag...)
|
||||
|
||||
data.ForwardingRules, diag = types.ListValueFrom(ctx,
|
||||
types.ObjectType{AttrTypes: resources.ForwardingRulesValue{}.AttributeTypes(ctx)},
|
||||
|
||||
@@ -2,8 +2,6 @@ package provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
@@ -16,13 +14,7 @@ import (
|
||||
|
||||
func TestLoadBalancerResource(t *testing.T) {
|
||||
// Must assign a password to the server or Binary Lane will send emails
|
||||
pw_bytes := make([]byte, 12)
|
||||
_, err := rand.Read(pw_bytes)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to generate password: %s", err)
|
||||
return
|
||||
}
|
||||
password := base64.URLEncoding.EncodeToString(pw_bytes)
|
||||
password := GenerateTestPassword(t)
|
||||
|
||||
resource.ParallelTest(t, resource.TestCase{
|
||||
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
|
||||
@@ -43,7 +35,7 @@ resource "binarylane_server" "test" {
|
||||
resource "binarylane_load_balancer" "test" {
|
||||
name = "tf-test-lb"
|
||||
server_ids = [binarylane_server.test.0.id, binarylane_server.test.1.id]
|
||||
forwarding_rules = [{ entry_protocol = "http" }]
|
||||
# initially, skip defining forwarding_rules, health_check, to test default values
|
||||
}
|
||||
|
||||
data "binarylane_load_balancer" "test" {
|
||||
@@ -62,6 +54,9 @@ data "binarylane_load_balancer" "test" {
|
||||
resource.TestCheckResourceAttrPair("binarylane_load_balancer.test", "server_ids.1", "binarylane_server.test.1", "id"),
|
||||
resource.TestCheckResourceAttr("binarylane_load_balancer.test", "forwarding_rules.#", "1"),
|
||||
resource.TestCheckResourceAttr("binarylane_load_balancer.test", "forwarding_rules.0.entry_protocol", "http"),
|
||||
resource.TestCheckResourceAttr("binarylane_load_balancer.test", "health_check.path", "/"),
|
||||
resource.TestCheckResourceAttr("binarylane_load_balancer.test", "health_check.protocol", "http"),
|
||||
resource.TestCheckResourceAttrSet("binarylane_load_balancer.test", "ip"),
|
||||
|
||||
// Verify data source values
|
||||
resource.TestCheckResourceAttrPair("data.binarylane_load_balancer.test", "id", "binarylane_load_balancer.test", "id"),
|
||||
@@ -72,6 +67,9 @@ data "binarylane_load_balancer" "test" {
|
||||
resource.TestCheckResourceAttrPair("data.binarylane_load_balancer.test", "server_ids.1", "binarylane_server.test.1", "id"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_load_balancer.test", "forwarding_rules.#", "1"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_load_balancer.test", "forwarding_rules.0.entry_protocol", "http"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_load_balancer.test", "health_check.path", "/"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_load_balancer.test", "health_check.protocol", "http"),
|
||||
resource.TestCheckResourceAttrSet("data.binarylane_load_balancer.test", "ip"),
|
||||
),
|
||||
},
|
||||
// Test import by ID
|
||||
@@ -87,6 +85,63 @@ data "binarylane_load_balancer" "test" {
|
||||
ImportStateId: "tf-test-lb",
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
{
|
||||
Config: providerConfig + `
|
||||
resource "binarylane_server" "test" {
|
||||
count = 2
|
||||
name = "tf-test-lb-server-${count.index}"
|
||||
region = "per"
|
||||
image = "debian-12"
|
||||
size = "std-min"
|
||||
password = "` + password + `"
|
||||
public_ipv4_count = 1
|
||||
}
|
||||
|
||||
resource "binarylane_load_balancer" "test" {
|
||||
name = "tf-test-lb"
|
||||
server_ids = [binarylane_server.test.0.id, binarylane_server.test.1.id]
|
||||
# updated
|
||||
forwarding_rules = [{ entry_protocol = "https" }]
|
||||
health_check = {
|
||||
path = "/test-health"
|
||||
protocol = "https"
|
||||
}
|
||||
}
|
||||
|
||||
data "binarylane_load_balancer" "test" {
|
||||
depends_on = [binarylane_load_balancer.test]
|
||||
|
||||
id = binarylane_load_balancer.test.id
|
||||
}
|
||||
`,
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
// Verify resource values
|
||||
resource.TestCheckResourceAttrSet("binarylane_load_balancer.test", "id"),
|
||||
resource.TestCheckResourceAttr("binarylane_load_balancer.test", "name", "tf-test-lb"),
|
||||
resource.TestCheckNoResourceAttr("binarylane_load_balancer.test", "region"),
|
||||
resource.TestCheckResourceAttr("binarylane_load_balancer.test", "server_ids.#", "2"),
|
||||
resource.TestCheckResourceAttrPair("binarylane_load_balancer.test", "server_ids.0", "binarylane_server.test.0", "id"),
|
||||
resource.TestCheckResourceAttrPair("binarylane_load_balancer.test", "server_ids.1", "binarylane_server.test.1", "id"),
|
||||
resource.TestCheckResourceAttr("binarylane_load_balancer.test", "forwarding_rules.#", "1"),
|
||||
resource.TestCheckResourceAttr("binarylane_load_balancer.test", "forwarding_rules.0.entry_protocol", "https"),
|
||||
resource.TestCheckResourceAttr("binarylane_load_balancer.test", "health_check.path", "/test-health"),
|
||||
resource.TestCheckResourceAttr("binarylane_load_balancer.test", "health_check.protocol", "https"),
|
||||
resource.TestCheckResourceAttrSet("binarylane_load_balancer.test", "ip"),
|
||||
|
||||
// Verify data source values
|
||||
resource.TestCheckResourceAttrPair("data.binarylane_load_balancer.test", "id", "binarylane_load_balancer.test", "id"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_load_balancer.test", "name", "tf-test-lb"),
|
||||
resource.TestCheckNoResourceAttr("data.binarylane_load_balancer.test", "region"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_load_balancer.test", "server_ids.#", "2"),
|
||||
resource.TestCheckResourceAttrPair("data.binarylane_load_balancer.test", "server_ids.0", "binarylane_server.test.0", "id"),
|
||||
resource.TestCheckResourceAttrPair("data.binarylane_load_balancer.test", "server_ids.1", "binarylane_server.test.1", "id"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_load_balancer.test", "forwarding_rules.#", "1"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_load_balancer.test", "forwarding_rules.0.entry_protocol", "https"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_load_balancer.test", "health_check.path", "/test-health"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_load_balancer.test", "health_check.protocol", "https"),
|
||||
resource.TestCheckResourceAttrSet("data.binarylane_load_balancer.test", "ip"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -125,15 +180,15 @@ func init() {
|
||||
|
||||
loadBalancers := *listResp.JSON200.LoadBalancers
|
||||
for _, lb := range loadBalancers {
|
||||
if strings.HasPrefix(*lb.Name, "tf-test-") {
|
||||
deleteResp, err := client.DeleteLoadBalancersLoadBalancerIdWithResponse(ctx, *lb.Id)
|
||||
if strings.HasPrefix(lb.Name, "tf-test-") {
|
||||
deleteResp, err := client.DeleteLoadBalancersLoadBalancerIdWithResponse(ctx, lb.Id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting load balancer %d for test sweep: %w", *lb.Id, err)
|
||||
return fmt.Errorf("Error deleting load balancer %d for test sweep: %w", lb.Id, err)
|
||||
}
|
||||
if deleteResp.StatusCode() != http.StatusNoContent {
|
||||
return fmt.Errorf("Unexpected status %d deleting load balancer %d in test sweep: %s", deleteResp.StatusCode(), *lb.Id, deleteResp.Body)
|
||||
return fmt.Errorf("Unexpected status %d deleting load balancer %d in test sweep: %s", deleteResp.StatusCode(), lb.Id, deleteResp.Body)
|
||||
}
|
||||
log.Println("Deleted load balancer during test sweep:", *lb.Id)
|
||||
log.Println("Deleted load balancer during test sweep:", lb.Id)
|
||||
}
|
||||
}
|
||||
if listResp.JSON200.Links == nil || listResp.JSON200.Links.Pages == nil || listResp.JSON200.Links.Pages.Next == nil {
|
||||
|
||||
@@ -41,12 +41,12 @@ func (p *binarylaneProvider) Schema(_ context.Context, _ provider.SchemaRequest,
|
||||
resp.Schema = schema.Schema{
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"api_endpoint": schema.StringAttribute{
|
||||
MarkdownDescription: "Binary Lane API endpoint. If not set checks env for `BINARYLANE_API_ENDPOINT`. " +
|
||||
"Default: `https://api.binarylane.com.au/v2`.",
|
||||
MarkdownDescription: "Binary Lane API endpoint. Defaults to `https://api.binarylane.com.au/v2`, but can be " +
|
||||
"overridden by setting this attribute or the `BINARYLANE_API_ENDPOINT` environment variable.",
|
||||
Optional: true,
|
||||
},
|
||||
"api_token": schema.StringAttribute{
|
||||
MarkdownDescription: "Binary Lane API token. If not set checks env for `BINARYLANE_API_TOKEN`.",
|
||||
MarkdownDescription: "Binary Lane API token. If not defined, will default to `BINARYLANE_API_TOKEN` environment variable.",
|
||||
Optional: true,
|
||||
Sensitive: true,
|
||||
},
|
||||
@@ -93,6 +93,9 @@ func (p *binarylaneProvider) DataSources(_ context.Context) []func() datasource.
|
||||
NewVpcDataSource,
|
||||
NewVpcRouteEntriesDataSource,
|
||||
NewLoadBalancerDataSource,
|
||||
NewImagesDataSource,
|
||||
NewRegionsDataSource,
|
||||
NewSizesDataSource,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"terraform-provider-binarylane/internal/binarylane"
|
||||
"terraform-provider-binarylane/internal/data_sources"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework/datasource"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
)
|
||||
|
||||
var (
|
||||
_ datasource.DataSource = ®ionsDataSource{}
|
||||
_ datasource.DataSourceWithConfigure = ®ionsDataSource{}
|
||||
)
|
||||
|
||||
func NewRegionsDataSource() datasource.DataSource {
|
||||
return ®ionsDataSource{}
|
||||
}
|
||||
|
||||
type regionsDataSource struct {
|
||||
bc *BinarylaneClient
|
||||
}
|
||||
|
||||
type regionsDataSourceModel struct {
|
||||
data_sources.RegionsModel
|
||||
}
|
||||
|
||||
func (d *regionsDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
|
||||
resp.TypeName = req.ProviderTypeName + "_regions"
|
||||
}
|
||||
|
||||
func (d *regionsDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
|
||||
if req.ProviderData == nil {
|
||||
return
|
||||
}
|
||||
|
||||
bc, ok := req.ProviderData.(BinarylaneClient)
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected Data Source Configure Type",
|
||||
fmt.Sprintf("Expected *BinarylaneClient, got: %T.", req.ProviderData))
|
||||
return
|
||||
}
|
||||
|
||||
d.bc = &bc
|
||||
}
|
||||
|
||||
func (d *regionsDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
|
||||
resp.Schema = data_sources.RegionsDataSourceSchema(ctx)
|
||||
}
|
||||
|
||||
func (d *regionsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
|
||||
var data regionsDataSourceModel
|
||||
|
||||
// Read Terraform configuration data into the model
|
||||
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
// Read API call logic
|
||||
var page int32 = 1
|
||||
perPage := int32(200)
|
||||
var nextPage bool = true
|
||||
var regResults []binarylane.Region
|
||||
|
||||
for nextPage {
|
||||
params := binarylane.GetRegionsParams{
|
||||
Page: &page,
|
||||
PerPage: &perPage,
|
||||
}
|
||||
listResp, err := d.bc.client.GetRegionsWithResponse(ctx, ¶ms)
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError("Error listing regions", err.Error())
|
||||
return
|
||||
}
|
||||
if listResp.StatusCode() != http.StatusOK {
|
||||
resp.Diagnostics.AddError("Unexpected status code listing regions", string(listResp.Body))
|
||||
return
|
||||
}
|
||||
regResults = append(regResults, listResp.JSON200.Regions...)
|
||||
|
||||
if listResp.JSON200.Links == nil || listResp.JSON200.Links.Pages == nil || listResp.JSON200.Links.Pages.Next == nil {
|
||||
nextPage = false
|
||||
break
|
||||
}
|
||||
page++
|
||||
}
|
||||
|
||||
regions, diags := types.ListValueFrom(ctx, data.Regions.ElementType(ctx), regResults)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
data.Regions = regions
|
||||
|
||||
// Save data into Terraform state
|
||||
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
|
||||
)
|
||||
|
||||
func TestRegionsDataSource(t *testing.T) {
|
||||
resource.ParallelTest(t, resource.TestCase{
|
||||
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
|
||||
Steps: []resource.TestStep{
|
||||
// Create and Read testing
|
||||
{
|
||||
Config: providerConfig + `
|
||||
data "binarylane_regions" "test" {
|
||||
}
|
||||
`,
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
// Verify data source values
|
||||
resource.TestCheckResourceAttrWith("data.binarylane_regions.test", "regions.#", func(value string) error {
|
||||
count, err := strconv.Atoi(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if count < 1 {
|
||||
return fmt.Errorf("expected at least one region, got: %d", count)
|
||||
}
|
||||
return nil
|
||||
}),
|
||||
resource.TestCheckResourceAttrSet("data.binarylane_regions.test", "regions.0.slug"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -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,9 +29,14 @@ 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"`
|
||||
PublicIpv4Addresses types.List `tfsdk:"public_ipv4_addresses"`
|
||||
PrivateIPv4Addresses types.List `tfsdk:"private_ipv4_addresses"`
|
||||
PublicIpv6Addresses types.List `tfsdk:"public_ipv6_addresses"`
|
||||
PrivateIpv6Addresses types.List `tfsdk:"private_ipv6_addresses"`
|
||||
Permalink types.String `tfsdk:"permalink"`
|
||||
Memory types.Int32 `tfsdk:"memory"`
|
||||
Disk types.Int32 `tfsdk:"disk"`
|
||||
SourceAndDestinationCheck types.Bool `tfsdk:"source_and_destination_check"`
|
||||
}
|
||||
|
||||
func (d *serverDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
|
||||
@@ -56,51 +63,21 @@ 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())
|
||||
return
|
||||
}
|
||||
resp.Schema = *ds
|
||||
resp.Schema.Description = "Provides a Binary Lane Server data source. This can be used to read existing server details."
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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",
|
||||
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,
|
||||
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,
|
||||
Computed: true,
|
||||
}
|
||||
resp.Schema.Description = "Retrieve details about a BinaryLane Server."
|
||||
}
|
||||
|
||||
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
|
||||
@@ -128,16 +105,41 @@ func (d *serverDataSource) Read(ctx context.Context, req datasource.ReadRequest,
|
||||
return
|
||||
}
|
||||
|
||||
// Set data values
|
||||
data.Id = types.Int64Value(*serverResp.JSON200.Server.Id)
|
||||
data.Name = types.StringValue(*serverResp.JSON200.Server.Name)
|
||||
data.Image = types.StringValue(*serverResp.JSON200.Server.Image.Slug)
|
||||
data.Region = types.StringValue(*serverResp.JSON200.Server.Region.Slug)
|
||||
data.Size = types.StringValue(*serverResp.JSON200.Server.Size.Slug)
|
||||
data.Backups = types.BoolValue(serverResp.JSON200.Server.NextBackupWindow != nil)
|
||||
data.Ipv6 = types.BoolValue(len(serverResp.JSON200.Server.Networks.V6) > 0)
|
||||
data.PortBlocking = types.BoolValue(serverResp.JSON200.Server.Networks.PortBlocking)
|
||||
data.VpcId = types.Int64PointerValue(serverResp.JSON200.Server.VpcId)
|
||||
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)
|
||||
|
||||
var publicIpv4Addresses []string
|
||||
var privateIpv4Addresses []string
|
||||
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{}
|
||||
|
||||
for _, v4address := range serverResp.JSON200.Server.Networks.V4 {
|
||||
if v4address.Type == "public" {
|
||||
@@ -146,10 +148,49 @@ func (d *serverDataSource) Read(ctx context.Context, req datasource.ReadRequest,
|
||||
privateIpv4Addresses = append(privateIpv4Addresses, v4address.IpAddress)
|
||||
}
|
||||
}
|
||||
data.PublicIpv4Addresses, diags = types.ListValueFrom(ctx, types.StringType, publicIpv4Addresses)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
data.PrivateIPv4Addresses, diags = types.ListValueFrom(ctx, types.StringType, privateIpv4Addresses)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
|
||||
tfPublicIpv4Addresses, diag := types.ListValueFrom(ctx, types.StringType, publicIpv4Addresses)
|
||||
diags.Append(diag...)
|
||||
if diag.HasError() {
|
||||
data.PublicIpv4Addresses = types.ListUnknown(data.PublicIpv4Addresses.ElementType(ctx))
|
||||
} else {
|
||||
data.PublicIpv4Addresses = tfPublicIpv4Addresses
|
||||
}
|
||||
|
||||
tfPrivateIpv4Addresses, diag := types.ListValueFrom(ctx, types.StringType, privateIpv4Addresses)
|
||||
diags.Append(diag...)
|
||||
if diag.HasError() {
|
||||
data.PrivateIPv4Addresses = types.ListUnknown(data.PrivateIPv4Addresses.ElementType(ctx))
|
||||
} else {
|
||||
data.PrivateIPv4Addresses = tfPrivateIpv4Addresses
|
||||
}
|
||||
|
||||
publicIpv6Addresses := []string{}
|
||||
privateIpv6Addresses := []string{}
|
||||
|
||||
for _, v6address := range serverResp.JSON200.Server.Networks.V6 {
|
||||
if v6address.Type == "public" {
|
||||
publicIpv6Addresses = append(publicIpv6Addresses, v6address.IpAddress)
|
||||
} else {
|
||||
privateIpv6Addresses = append(privateIpv6Addresses, v6address.IpAddress)
|
||||
}
|
||||
}
|
||||
|
||||
tfPublicIpv6Addresses, diag := types.ListValueFrom(ctx, types.StringType, publicIpv6Addresses)
|
||||
diags.Append(diag...)
|
||||
if diag.HasError() {
|
||||
data.PublicIpv6Addresses = types.ListUnknown(data.PublicIpv6Addresses.ElementType(ctx))
|
||||
} else {
|
||||
data.PublicIpv6Addresses = tfPublicIpv6Addresses
|
||||
}
|
||||
|
||||
tfPrivateIpv6Addresses, diag := types.ListValueFrom(ctx, types.StringType, privateIpv6Addresses)
|
||||
diags.Append(diag...)
|
||||
if diag.HasError() {
|
||||
data.PrivateIpv6Addresses = types.ListUnknown(data.PrivateIpv6Addresses.ElementType(ctx))
|
||||
} else {
|
||||
data.PrivateIpv6Addresses = tfPrivateIpv6Addresses
|
||||
}
|
||||
|
||||
// Get user data script
|
||||
userDataResp, err := d.bc.client.GetServersServerIdUserDataWithResponse(ctx, data.Id.ValueInt64())
|
||||
|
||||
@@ -43,7 +43,7 @@ func (d *serverFirewallRulesDataSource) Schema(ctx context.Context, req datasour
|
||||
return
|
||||
}
|
||||
resp.Schema = *ds
|
||||
resp.Schema.Description = "TODO"
|
||||
resp.Schema.Description = "Retrieve details about the External Firewall Rules assigned to a BinaryLane server."
|
||||
}
|
||||
|
||||
func (d *serverFirewallRulesDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
|
||||
|
||||
@@ -59,11 +59,11 @@ func (r *serverFirewallRulesResource) Metadata(ctx context.Context, req resource
|
||||
|
||||
func (r *serverFirewallRulesResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
|
||||
resp.Schema = resources.ServerFirewallRulesResourceSchema(ctx)
|
||||
// resp.Schema.Description = "TODO"
|
||||
resp.Schema.Description = "Retrieve details about the External Firewall Rules assigned to a BinaryLane server."
|
||||
|
||||
// Overrides
|
||||
serverId := resp.Schema.Attributes["server_id"]
|
||||
resp.Schema.Attributes["server_id"] = &schema.Int64Attribute{
|
||||
resp.Schema.Attributes["server_id"] = schema.Int64Attribute{
|
||||
Description: serverId.GetDescription(),
|
||||
MarkdownDescription: serverId.GetMarkdownDescription(),
|
||||
Required: true, // Server ID is required to define the firewall rules
|
||||
@@ -83,7 +83,7 @@ func (r *serverFirewallRulesResource) Create(ctx context.Context, req resource.C
|
||||
}
|
||||
|
||||
// Create API call logic
|
||||
firewallRules := []binarylane.AdvancedFirewallRule{}
|
||||
firewallRules := []binarylane.AdvancedFirewallRuleRequest{}
|
||||
diags := data.FirewallRules.ElementsAs(ctx, &firewallRules, true)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -169,7 +174,7 @@ func (r *serverFirewallRulesResource) Update(ctx context.Context, req resource.U
|
||||
}
|
||||
|
||||
// Update API call logic
|
||||
firewallRules := []binarylane.AdvancedFirewallRule{}
|
||||
firewallRules := []binarylane.AdvancedFirewallRuleRequest{}
|
||||
diags := data.FirewallRules.ElementsAs(ctx, &firewallRules, true)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
@@ -223,7 +228,7 @@ func (r *serverFirewallRulesResource) Delete(ctx context.Context, req resource.D
|
||||
data.ServerId.ValueInt64(),
|
||||
binarylane.PostServersServerIdActionsChangeAdvancedFirewallRulesJSONRequestBody{
|
||||
Type: "change_advanced_firewall_rules",
|
||||
FirewallRules: []binarylane.AdvancedFirewallRule{},
|
||||
FirewallRules: []binarylane.AdvancedFirewallRuleRequest{},
|
||||
})
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError(
|
||||
@@ -246,7 +251,7 @@ func GetFirewallRulesState(ctx context.Context, firewallRules *[]binarylane.Adva
|
||||
firewallRulesValue := resources.FirewallRulesValue{}
|
||||
var firewallRulesValues []resources.FirewallRulesValue
|
||||
|
||||
if *firewallRules == nil || len(*firewallRules) == 0 {
|
||||
if len(*firewallRules) == 0 {
|
||||
firewallRulesValues = []resources.FirewallRulesValue{}
|
||||
} else {
|
||||
for _, rule := range *firewallRules {
|
||||
@@ -266,6 +271,7 @@ func GetFirewallRulesState(ctx context.Context, firewallRules *[]binarylane.Adva
|
||||
return basetypes.NewListUnknown(firewallRulesValue.Type(ctx)), diags
|
||||
}
|
||||
|
||||
// TODO: This panics if invalid, should be handled better
|
||||
ruleValue := resources.NewFirewallRulesValueMust(firewallRulesValue.AttributeTypes(ctx), map[string]attr.Value{
|
||||
"description": types.StringPointerValue(rule.Description),
|
||||
"action": types.StringValue(string(rule.Action)),
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
|
||||
@@ -11,9 +9,7 @@ import (
|
||||
|
||||
func TestServerFirewallRulesResource(t *testing.T) {
|
||||
// Must assign a password to the server or Binary Lane will send emails
|
||||
pw_bytes := make([]byte, 12)
|
||||
rand.Read(pw_bytes)
|
||||
password := base64.URLEncoding.EncodeToString(pw_bytes)
|
||||
password := GenerateTestPassword(t)
|
||||
|
||||
resource.ParallelTest(t, resource.TestCase{
|
||||
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
|
||||
@@ -78,11 +74,6 @@ data "binarylane_server_firewall_rules" "test" {
|
||||
),
|
||||
},
|
||||
// ImportState testing
|
||||
// {
|
||||
// ResourceName: "binarylane_server.test",
|
||||
// ImportState: true,
|
||||
// ImportStateVerify: true,
|
||||
// },
|
||||
{
|
||||
ResourceName: "binarylane_server_firewall_rules.test",
|
||||
ImportState: true,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,16 +16,11 @@ import (
|
||||
|
||||
func TestServerResource(t *testing.T) {
|
||||
// Must assign a password to the server or Binary Lane will send emails
|
||||
pw_bytes := make([]byte, 12)
|
||||
_, err := rand.Read(pw_bytes)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to generate password: %s", err)
|
||||
return
|
||||
}
|
||||
password := base64.URLEncoding.EncodeToString(pw_bytes)
|
||||
password1 := GenerateTestPassword(t)
|
||||
password2 := GenerateTestPassword(t)
|
||||
|
||||
sshPublicKeyInitial := GeneratePublicKey(t)
|
||||
sshPublicKeyUpdated := GeneratePublicKey(t)
|
||||
sshPublicKeyInitial := GenerateTestPublicKey(t)
|
||||
sshPublicKeyUpdated := GenerateTestPublicKey(t)
|
||||
|
||||
resource.ParallelTest(t, resource.TestCase{
|
||||
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
|
||||
@@ -56,10 +51,14 @@ resource "binarylane_server" "test" {
|
||||
region = "per"
|
||||
image = "debian-11"
|
||||
size = "std-min"
|
||||
password = "` + password + `"
|
||||
memory = 1152
|
||||
password = "` + password1 + `"
|
||||
vpc_id = binarylane_vpc.test.id
|
||||
public_ipv4_count = 1
|
||||
ssh_keys = [binarylane_ssh_key.initial.id]
|
||||
source_and_destination_check = false
|
||||
backups = true
|
||||
port_blocking = false
|
||||
user_data = <<EOT
|
||||
#cloud-config
|
||||
echo "Hello World" > /var/tmp/output.txt
|
||||
@@ -79,18 +78,34 @@ data "binarylane_server" "test" {
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "region", "per"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "image", "debian-11"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "size", "std-min"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "memory", "1152"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disk", "20"),
|
||||
resource.TestCheckResourceAttrSet("binarylane_server.test", "vpc_id"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "public_ipv4_count", "1"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "password", password),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "password", password1),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "user_data", `#cloud-config
|
||||
echo "Hello World" > /var/tmp/output.txt
|
||||
`),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "public_ipv4_addresses.#", "1"),
|
||||
resource.TestCheckResourceAttrSet("binarylane_server.test", "private_ipv4_addresses.0"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "port_blocking", "true"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "port_blocking", "false"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "ssh_keys.#", "1"),
|
||||
resource.TestCheckResourceAttrPair("binarylane_server.test", "ssh_keys.0", "binarylane_ssh_key.initial", "id"),
|
||||
resource.TestCheckResourceAttrSet("binarylane_server.test", "permalink"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "source_and_destination_check", "false"),
|
||||
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"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "ipv6", "false"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "public_ipv6_addresses.#", "0"),
|
||||
|
||||
// Verify data source values
|
||||
resource.TestCheckResourceAttrPair("data.binarylane_server.test", "id", "binarylane_server.test", "id"),
|
||||
@@ -98,10 +113,27 @@ echo "Hello World" > /var/tmp/output.txt
|
||||
resource.TestCheckResourceAttr("data.binarylane_server.test", "region", "per"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_server.test", "image", "debian-11"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_server.test", "size", "std-min"),
|
||||
resource.TestCheckResourceAttrSet("data.binarylane_server.test", "vpc_id"),
|
||||
resource.TestCheckResourceAttrPair("data.binarylane_server.test", "permalink", "binarylane_server.test", "permalink"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_server.test", "user_data", `#cloud-config
|
||||
echo "Hello World" > /var/tmp/output.txt
|
||||
`),
|
||||
resource.TestCheckResourceAttr("data.binarylane_server.test", "memory", "1152"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_server.test", "disk", "20"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_server.test", "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"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_server.test", "ipv6", "false"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_server.test", "public_ipv6_addresses.#", "0"),
|
||||
),
|
||||
},
|
||||
// Test import by ID
|
||||
@@ -144,10 +176,20 @@ resource "binarylane_server" "test" {
|
||||
region = "per"
|
||||
image = "debian-12"
|
||||
size = "std-1vcpu"
|
||||
password = "` + password + `"
|
||||
vpc_id = binarylane_vpc.test.id
|
||||
disk = "45"
|
||||
password = "` + password1 + `"
|
||||
vpc_id = null
|
||||
public_ipv4_count = 0
|
||||
ssh_keys = [binarylane_ssh_key.updated.id]
|
||||
advanced_features = {
|
||||
emulated_hyperv = true
|
||||
}
|
||||
ipv6 = true
|
||||
|
||||
# source_and_destination_check = null # defaults to null
|
||||
# backups = false # defaults to false
|
||||
# port_blocking = true # defaults to true
|
||||
|
||||
user_data = <<EOT
|
||||
#cloud-config
|
||||
echo "Hello Whitespace" > /var/tmp/output.txt
|
||||
@@ -159,23 +201,136 @@ EOT
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "name", "tf-test-server-resource-2"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "size", "std-1vcpu"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "memory", "2048"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "disk", "45"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "public_ipv4_count", "0"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "public_ipv4_addresses.#", "0"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "image", "debian-12"),
|
||||
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"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "user_data", // test extra whitespace
|
||||
`#cloud-config
|
||||
echo "Hello Whitespace" > /var/tmp/output.txt
|
||||
|
||||
|
||||
`),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "ipv6", "true"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "public_ipv6_addresses.#", "1"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "private_ipv6_addresses.#", "1"),
|
||||
),
|
||||
},
|
||||
// Change password testing (Cannot run at same time as Rebuild operation, so it has it's own test)
|
||||
{
|
||||
Config: providerConfig + `
|
||||
resource "binarylane_vpc" "test" {
|
||||
name = "tf-test-server-resource"
|
||||
ip_range = "10.240.0.0/16"
|
||||
}
|
||||
|
||||
resource "binarylane_ssh_key" "initial" {
|
||||
name = "tf-test-server-resource-initial"
|
||||
public_key = "` + sshPublicKeyInitial + `"
|
||||
default = true
|
||||
}
|
||||
|
||||
resource "binarylane_ssh_key" "updated" {
|
||||
name = "tf-test-server-resource-updated"
|
||||
public_key = "` + sshPublicKeyUpdated + `"
|
||||
default = true
|
||||
}
|
||||
|
||||
resource "binarylane_server" "test" {
|
||||
name = "tf-test-server-resource-2"
|
||||
region = "per"
|
||||
image = "debian-12"
|
||||
size = "std-1vcpu"
|
||||
disk = "45"
|
||||
password = "` + password2 + `"
|
||||
vpc_id = null
|
||||
public_ipv4_count = 0
|
||||
ssh_keys = [binarylane_ssh_key.updated.id]
|
||||
|
||||
# source_and_destination_check = null # defaults to null
|
||||
# backups = false # defaults to false
|
||||
# port_blocking = true # defaults to true
|
||||
|
||||
user_data = <<EOT
|
||||
#cloud-config
|
||||
echo "Hello Whitespace" > /var/tmp/output.txt
|
||||
|
||||
|
||||
EOT
|
||||
}
|
||||
`,
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "name", "tf-test-server-resource-2"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "password", password2),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestServerResourceRename(t *testing.T) {
|
||||
// Must assign a password to the server or Binary Lane will send emails
|
||||
password := GenerateTestPassword(t)
|
||||
|
||||
resource.ParallelTest(t, resource.TestCase{
|
||||
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
|
||||
Steps: []resource.TestStep{
|
||||
// Setup
|
||||
{
|
||||
Config: providerConfig + `
|
||||
|
||||
resource "binarylane_server" "test" {
|
||||
name = "tf-test-server-rename-1"
|
||||
region = "per"
|
||||
image = "debian-11"
|
||||
size = "std-min"
|
||||
public_ipv4_count = 0
|
||||
password = "` + password + `"
|
||||
}
|
||||
`,
|
||||
},
|
||||
// Rename
|
||||
{
|
||||
Config: providerConfig + `
|
||||
resource "binarylane_server" "test" {
|
||||
name = "tf-test-server-rename-2"
|
||||
region = "per"
|
||||
image = "debian-11"
|
||||
size = "std-min"
|
||||
public_ipv4_count = 0
|
||||
password = "` + password + `"
|
||||
}
|
||||
`,
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "name", "tf-test-server-rename-2"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "region", "per"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "image", "debian-11"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "size", "std-min"),
|
||||
resource.TestCheckResourceAttr("binarylane_server.test", "password", password),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func GenerateTestPassword(t *testing.T) string {
|
||||
t.Helper()
|
||||
pwBytes := make([]byte, 12)
|
||||
_, err := rand.Read(pwBytes)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to generate password: %s", err)
|
||||
}
|
||||
return base64.URLEncoding.EncodeToString(pwBytes)
|
||||
}
|
||||
|
||||
func init() {
|
||||
resource.AddTestSweepers("server", &resource.Sweeper{
|
||||
Name: "server",
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"terraform-provider-binarylane/internal/binarylane"
|
||||
"terraform-provider-binarylane/internal/data_sources"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework/datasource"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
)
|
||||
|
||||
var (
|
||||
_ datasource.DataSource = &sizesDataSource{}
|
||||
_ datasource.DataSourceWithConfigure = &sizesDataSource{}
|
||||
)
|
||||
|
||||
func NewSizesDataSource() datasource.DataSource {
|
||||
return &sizesDataSource{}
|
||||
}
|
||||
|
||||
type sizesDataSource struct {
|
||||
bc *BinarylaneClient
|
||||
}
|
||||
|
||||
type sizesDataSourceModel struct {
|
||||
data_sources.SizesModel
|
||||
}
|
||||
|
||||
func (d *sizesDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
|
||||
resp.TypeName = req.ProviderTypeName + "_sizes"
|
||||
}
|
||||
|
||||
func (d *sizesDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
|
||||
if req.ProviderData == nil {
|
||||
return
|
||||
}
|
||||
|
||||
bc, ok := req.ProviderData.(BinarylaneClient)
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected Data Source Configure Type",
|
||||
fmt.Sprintf("Expected *BinarylaneClient, got: %T.", req.ProviderData))
|
||||
return
|
||||
}
|
||||
|
||||
d.bc = &bc
|
||||
}
|
||||
|
||||
func (d *sizesDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
|
||||
resp.Schema = data_sources.SizesDataSourceSchema(ctx)
|
||||
}
|
||||
|
||||
func (d *sizesDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
|
||||
var data sizesDataSourceModel
|
||||
|
||||
// Read Terraform configuration data into the model
|
||||
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
// Read API call logic
|
||||
var page int32 = 1
|
||||
perPage := int32(200)
|
||||
var nextPage bool = true
|
||||
var regResults []binarylane.Size
|
||||
|
||||
for nextPage {
|
||||
params := binarylane.GetSizesParams{
|
||||
Page: &page,
|
||||
PerPage: &perPage,
|
||||
}
|
||||
listResp, err := d.bc.client.GetSizesWithResponse(ctx, ¶ms)
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError("Error listing sizes", err.Error())
|
||||
return
|
||||
}
|
||||
if listResp.StatusCode() != http.StatusOK {
|
||||
resp.Diagnostics.AddError("Unexpected status code listing sizes", string(listResp.Body))
|
||||
return
|
||||
}
|
||||
regResults = append(regResults, listResp.JSON200.Sizes...)
|
||||
|
||||
if listResp.JSON200.Links == nil || listResp.JSON200.Links.Pages == nil || listResp.JSON200.Links.Pages.Next == nil {
|
||||
nextPage = false
|
||||
break
|
||||
}
|
||||
page++
|
||||
}
|
||||
|
||||
sizes, diags := types.ListValueFrom(ctx, data.Sizes.ElementType(ctx), regResults)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
data.Sizes = sizes
|
||||
|
||||
// Save data into Terraform state
|
||||
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
|
||||
)
|
||||
|
||||
func TestSizesDataSource(t *testing.T) {
|
||||
resource.ParallelTest(t, resource.TestCase{
|
||||
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
|
||||
Steps: []resource.TestStep{
|
||||
// Create and Read testing
|
||||
{
|
||||
Config: providerConfig + `
|
||||
data "binarylane_sizes" "test" {
|
||||
}
|
||||
`,
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
// Verify data source values
|
||||
resource.TestCheckResourceAttrWith("data.binarylane_sizes.test", "sizes.#", func(value string) error {
|
||||
count, err := strconv.Atoi(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if count < 1 {
|
||||
return fmt.Errorf("expected at least one size, got: %d", count)
|
||||
}
|
||||
return nil
|
||||
}),
|
||||
resource.TestCheckResourceAttrSet("data.binarylane_sizes.test", "sizes.0.slug"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -59,11 +59,30 @@ func (d *sshKeyDataSource) Schema(ctx context.Context, req datasource.SchemaRequ
|
||||
return
|
||||
}
|
||||
resp.Schema = *ds
|
||||
// resp.Schema.Description = "TODO"
|
||||
|
||||
// Overrides
|
||||
defaultDescription := "If `true`, this SSH key will be included on all new server installations (if the operating " +
|
||||
"system supports SSH key injection)."
|
||||
resp.Schema.Attributes["default"] = schema.BoolAttribute{
|
||||
Description: defaultDescription,
|
||||
MarkdownDescription: defaultDescription,
|
||||
Optional: false,
|
||||
Required: false,
|
||||
Computed: true,
|
||||
}
|
||||
|
||||
// Additional attributes
|
||||
publicKeyDescription := "The public key in OpenSSH \"authorized_keys\" format. This should be a valid public key, " +
|
||||
"such as one generated by `ssh-keygen`."
|
||||
resp.Schema.Attributes["public_key"] = schema.StringAttribute{
|
||||
Description: publicKeyDescription,
|
||||
MarkdownDescription: publicKeyDescription,
|
||||
CustomType: TrimmedStringType{},
|
||||
Computed: true,
|
||||
}
|
||||
|
||||
fingerprintDescription := "The fingerprint of the SSH key."
|
||||
resp.Schema.Attributes["fingerprint"] = &schema.StringAttribute{
|
||||
resp.Schema.Attributes["fingerprint"] = schema.StringAttribute{
|
||||
Description: fingerprintDescription,
|
||||
MarkdownDescription: fingerprintDescription,
|
||||
Optional: false,
|
||||
@@ -102,7 +121,9 @@ func (d *sshKeyDataSource) Read(ctx context.Context, req datasource.ReadRequest,
|
||||
data.Id = types.Int64Value(*sshResp.JSON200.SshKey.Id)
|
||||
data.Default = types.BoolValue(*sshResp.JSON200.SshKey.Default)
|
||||
data.Name = types.StringValue(*sshResp.JSON200.SshKey.Name)
|
||||
data.PublicKey = types.StringValue(*sshResp.JSON200.SshKey.PublicKey)
|
||||
data.PublicKey = TrimmedStringValue{
|
||||
StringValue: types.StringValue(*sshResp.JSON200.SshKey.PublicKey),
|
||||
}
|
||||
data.Fingerprint = types.StringValue(*sshResp.JSON200.SshKey.Fingerprint)
|
||||
|
||||
// Save data into Terraform state
|
||||
|
||||
@@ -12,9 +12,11 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier"
|
||||
"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.
|
||||
@@ -34,7 +36,8 @@ type sshKeyResource struct {
|
||||
|
||||
type sshKeyModel struct {
|
||||
resources.SshKeyModel
|
||||
Fingerprint types.String `tfsdk:"fingerprint"`
|
||||
Fingerprint types.String `tfsdk:"fingerprint"`
|
||||
PublicKey TrimmedStringValue `tfsdk:"public_key"`
|
||||
}
|
||||
|
||||
func (d *sshKeyResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
|
||||
@@ -61,34 +64,56 @@ func (r *sshKeyResource) Metadata(ctx context.Context, req resource.MetadataRequ
|
||||
|
||||
func (r *sshKeyResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
|
||||
resp.Schema = resources.SshKeyResourceSchema(ctx)
|
||||
// resp.Schema.Description = "TODO"
|
||||
|
||||
// Overrides
|
||||
default_ := resp.Schema.Attributes["default"]
|
||||
idDescription := "The numeric ID of the SSH key."
|
||||
resp.Schema.Attributes["id"] = schema.Int64Attribute{
|
||||
Required: false,
|
||||
Optional: false,
|
||||
Computed: true,
|
||||
Description: idDescription,
|
||||
MarkdownDescription: idDescription,
|
||||
PlanModifiers: []planmodifier.Int64{
|
||||
int64planmodifier.UseStateForUnknown(),
|
||||
},
|
||||
}
|
||||
|
||||
defaultDescription := "If `true`, this SSH key will be included on all new server installations (if the operating " +
|
||||
"system supports SSH key injection). Default is `false`."
|
||||
resp.Schema.Attributes["default"] = schema.BoolAttribute{
|
||||
Required: false,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
Description: default_.GetDescription(),
|
||||
MarkdownDescription: default_.GetMarkdownDescription(),
|
||||
Description: defaultDescription,
|
||||
MarkdownDescription: defaultDescription,
|
||||
Default: booldefault.StaticBool(false), // Add default to backups
|
||||
}
|
||||
|
||||
public_key := resp.Schema.Attributes["public_key"]
|
||||
// Additional attributes
|
||||
publicKeyDescription := "The public key in OpenSSH \"authorized_keys\" format. This should be a valid public key, " +
|
||||
"such as one generated by `ssh-keygen`."
|
||||
resp.Schema.Attributes["public_key"] = schema.StringAttribute{
|
||||
Required: true,
|
||||
Description: public_key.GetDescription(),
|
||||
MarkdownDescription: public_key.GetMarkdownDescription(),
|
||||
PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()},
|
||||
Optional: false,
|
||||
Computed: false,
|
||||
Description: publicKeyDescription,
|
||||
MarkdownDescription: publicKeyDescription,
|
||||
PlanModifiers: []planmodifier.String{
|
||||
RequiresReplaceForTrimmedStringModifier{},
|
||||
},
|
||||
CustomType: TrimmedStringType{}, // Ignore leading/trailing whitespace
|
||||
}
|
||||
|
||||
// Additional attributes
|
||||
fingerprintDescription := "The fingerprint of the SSH key."
|
||||
resp.Schema.Attributes["fingerprint"] = &schema.StringAttribute{
|
||||
resp.Schema.Attributes["fingerprint"] = schema.StringAttribute{
|
||||
Description: fingerprintDescription,
|
||||
MarkdownDescription: fingerprintDescription,
|
||||
Optional: false,
|
||||
Required: false,
|
||||
Computed: true,
|
||||
PlanModifiers: []planmodifier.String{
|
||||
stringplanmodifier.UseStateForUnknown(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,6 +139,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",
|
||||
@@ -139,9 +169,6 @@ func (r *sshKeyResource) Read(ctx context.Context, req resource.ReadRequest, res
|
||||
|
||||
// Read Terraform prior state data into the model
|
||||
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
|
||||
|
||||
data.PublicKey = types.StringValue(data.PublicKey.ValueString())
|
||||
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
@@ -167,7 +194,9 @@ func (r *sshKeyResource) Read(ctx context.Context, req resource.ReadRequest, res
|
||||
data.Id = types.Int64Value(*sshResp.JSON200.SshKey.Id)
|
||||
data.Default = types.BoolValue(*sshResp.JSON200.SshKey.Default)
|
||||
data.Name = types.StringValue(*sshResp.JSON200.SshKey.Name)
|
||||
data.PublicKey = types.StringValue(*sshResp.JSON200.SshKey.PublicKey)
|
||||
data.PublicKey = TrimmedStringValue{
|
||||
StringValue: types.StringValue(*sshResp.JSON200.SshKey.PublicKey),
|
||||
}
|
||||
data.Fingerprint = types.StringValue(*sshResp.JSON200.SshKey.Fingerprint)
|
||||
|
||||
// Save updated data into Terraform state
|
||||
@@ -190,27 +219,31 @@ func (r *sshKeyResource) Update(ctx context.Context, req resource.UpdateRequest,
|
||||
}
|
||||
|
||||
// Update API call logic
|
||||
sshResp, err := r.bc.client.PutAccountKeysKeyIdWithResponse(ctx, int(state.Id.ValueInt64()), binarylane.UpdateSshKeyRequest{
|
||||
Name: plan.Name.ValueString(),
|
||||
Default: plan.Default.ValueBoolPointer(),
|
||||
})
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError(
|
||||
fmt.Sprintf("Error updating SSH Key: name=%s", plan.Name.ValueString()),
|
||||
err.Error(),
|
||||
)
|
||||
return
|
||||
}
|
||||
if sshResp.StatusCode() != http.StatusOK {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected HTTP status code updating SSH Key",
|
||||
fmt.Sprintf("Received %s updating new SSH Key: name=%s. Details: %s", sshResp.Status(), plan.Name.ValueString(), sshResp.Body),
|
||||
)
|
||||
return
|
||||
if !state.Name.Equal(plan.Name) || !state.Default.Equal(plan.Default) {
|
||||
sshResp, err := r.bc.client.PutAccountKeysKeyIdWithResponse(ctx, int(state.Id.ValueInt64()), binarylane.UpdateSshKeyRequest{
|
||||
Name: plan.Name.ValueString(),
|
||||
Default: plan.Default.ValueBoolPointer(),
|
||||
})
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError(
|
||||
fmt.Sprintf("Error updating SSH Key: name=%s", plan.Name.ValueString()),
|
||||
err.Error(),
|
||||
)
|
||||
return
|
||||
}
|
||||
if sshResp.StatusCode() != http.StatusOK {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected HTTP status code updating SSH Key",
|
||||
fmt.Sprintf("Received %s updating new SSH Key: name=%s. Details: %s", sshResp.Status(), plan.Name.ValueString(), sshResp.Body),
|
||||
)
|
||||
return
|
||||
}
|
||||
state.Name = plan.Name
|
||||
state.Default = plan.Default
|
||||
}
|
||||
|
||||
// Save updated data into Terraform state
|
||||
resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
|
||||
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
|
||||
}
|
||||
|
||||
func (r *sshKeyResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
|
||||
@@ -265,7 +298,7 @@ func (r *sshKeyResource) ImportState(
|
||||
|
||||
sshResp, err := r.bc.client.GetAccountKeysWithResponse(ctx, ¶ms)
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError(fmt.Sprintf("Error getting SSH key for import: fingerprint=%s", req.ID), err.Error())
|
||||
resp.Diagnostics.AddError(fmt.Sprintf("Error getting SSH keys for import: fingerprint=%s", req.ID), err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -12,11 +12,12 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
|
||||
"github.com/hashicorp/terraform-plugin-testing/plancheck"
|
||||
"github.com/hashicorp/terraform-plugin-testing/terraform"
|
||||
)
|
||||
|
||||
func TestSshKeyResource(t *testing.T) {
|
||||
publicKey := GeneratePublicKey(t)
|
||||
publicKey := GenerateTestPublicKey(t)
|
||||
|
||||
resource.ParallelTest(t, resource.TestCase{
|
||||
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
|
||||
@@ -40,12 +41,14 @@ data "binarylane_ssh_key" "test" {
|
||||
// Verify resource values
|
||||
resource.TestCheckResourceAttr("binarylane_ssh_key.test", "name", "tf-test-key-resource-test"),
|
||||
resource.TestCheckResourceAttr("binarylane_ssh_key.test", "public_key", publicKey),
|
||||
resource.TestCheckResourceAttrSet("binarylane_ssh_key.test", "fingerprint"),
|
||||
resource.TestCheckResourceAttr("binarylane_ssh_key.test", "default", "false"),
|
||||
resource.TestCheckResourceAttrSet("binarylane_ssh_key.test", "id"),
|
||||
|
||||
// Verify data source values
|
||||
resource.TestCheckResourceAttr("data.binarylane_ssh_key.test", "name", "tf-test-key-resource-test"),
|
||||
resource.TestCheckResourceAttrSet("data.binarylane_ssh_key.test", "public_key"), // Ideally would check this is identical, but whitespace is not preserved
|
||||
resource.TestCheckResourceAttr("data.binarylane_ssh_key.test", "public_key", publicKey),
|
||||
resource.TestCheckResourceAttrSet("data.binarylane_ssh_key.test", "fingerprint"),
|
||||
resource.TestCheckResourceAttr("data.binarylane_ssh_key.test", "default", "false"),
|
||||
resource.TestCheckResourceAttrSet("data.binarylane_ssh_key.test", "id"),
|
||||
),
|
||||
@@ -64,27 +67,27 @@ data "binarylane_ssh_key" "test" {
|
||||
ImportStateVerify: true,
|
||||
ImportStateVerifyIgnore: []string{}, // nothing to ignore
|
||||
},
|
||||
// TODO: Update and Read testing
|
||||
// {
|
||||
// Config: providerConfig + `
|
||||
// resource "binarylane_ssh_key" "test" {
|
||||
// name = "tf-test-key-resource-test"
|
||||
// public_key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJCsuosklP0T4fJcQDgkeVh7dQu+eV+vev1CfwdUkj7h test@company.internal"
|
||||
// default = true
|
||||
// }
|
||||
// `,
|
||||
// Check: resource.ComposeAggregateTestCheckFunc(
|
||||
// // Verify resource values
|
||||
// resource.TestCheckResourceAttr("binarylane_ssh_key.test", "name", "tf-test-key-resource-test"),
|
||||
// resource.TestCheckResourceAttr("data.binarylane_ssh_key.test", "default", "true"),
|
||||
// ),
|
||||
// },
|
||||
// Delete testing automatically occurs in TestCase
|
||||
// Whitespace changes should not recreate the resource
|
||||
{
|
||||
Config: `
|
||||
resource "binarylane_ssh_key" "test" {
|
||||
name = "tf-test-key-resource-test"
|
||||
# Test public key with a newline to ensure it does not get recreated
|
||||
public_key = <<EOT
|
||||
` + publicKey + `
|
||||
EOT
|
||||
}`,
|
||||
ConfigPlanChecks: resource.ConfigPlanChecks{
|
||||
PreApply: []plancheck.PlanCheck{
|
||||
plancheck.ExpectEmptyPlan(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func GeneratePublicKey(t *testing.T) string {
|
||||
func GenerateTestPublicKey(t *testing.T) string {
|
||||
t.Helper()
|
||||
|
||||
pub, _, err := ed25519.GenerateKey(nil)
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework/attr"
|
||||
"github.com/hashicorp/terraform-plugin-framework/diag"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
|
||||
"github.com/hashicorp/terraform-plugin-go/tftypes"
|
||||
"github.com/hashicorp/terraform-plugin-log/tflog"
|
||||
)
|
||||
|
||||
// TrimmedStringType
|
||||
|
||||
// Ensure the implementation satisfies the expected interfaces
|
||||
var _ basetypes.StringTypable = TrimmedStringType{}
|
||||
|
||||
type TrimmedStringType struct {
|
||||
basetypes.StringType
|
||||
}
|
||||
|
||||
func (t TrimmedStringType) Equal(o attr.Type) bool {
|
||||
other, ok := o.(TrimmedStringType)
|
||||
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
return t.StringType.Equal(other.StringType)
|
||||
}
|
||||
|
||||
func (t TrimmedStringType) String() string {
|
||||
return "TrimmedStringType"
|
||||
}
|
||||
|
||||
func (t TrimmedStringType) ValueFromString(ctx context.Context, in basetypes.StringValue) (basetypes.StringValuable, diag.Diagnostics) {
|
||||
value := TrimmedStringValue{
|
||||
StringValue: in,
|
||||
}
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (t TrimmedStringType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) {
|
||||
attrValue, err := t.StringType.ValueFromTerraform(ctx, in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stringValue, ok := attrValue.(basetypes.StringValue)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected value type of %T", attrValue)
|
||||
}
|
||||
|
||||
stringValuable, diags := t.ValueFromString(ctx, stringValue)
|
||||
if diags.HasError() {
|
||||
return nil, fmt.Errorf("unexpected error converting StringValue to StringValuable: %v", diags)
|
||||
}
|
||||
|
||||
return stringValuable, nil
|
||||
}
|
||||
|
||||
func (t TrimmedStringType) ValueType(ctx context.Context) attr.Value {
|
||||
return TrimmedStringValue{}
|
||||
}
|
||||
|
||||
// TrimmedStringValue
|
||||
|
||||
var _ basetypes.StringValuable = TrimmedStringValue{}
|
||||
var _ basetypes.StringValuableWithSemanticEquals = TrimmedStringValue{}
|
||||
|
||||
type TrimmedStringValue struct {
|
||||
basetypes.StringValue
|
||||
}
|
||||
|
||||
func (v TrimmedStringValue) Equal(o attr.Value) bool {
|
||||
other, ok := o.(TrimmedStringValue)
|
||||
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
return v.StringValue.Equal(other.StringValue)
|
||||
}
|
||||
|
||||
func (v TrimmedStringValue) Type(ctx context.Context) attr.Type {
|
||||
return TrimmedStringType{}
|
||||
}
|
||||
|
||||
func (v TrimmedStringValue) StringSemanticEquals(ctx context.Context, newValuable basetypes.StringValuable) (bool, diag.Diagnostics) {
|
||||
var diags diag.Diagnostics
|
||||
|
||||
// The framework should always pass the correct value type, but always check
|
||||
newValue, ok := newValuable.(TrimmedStringValue)
|
||||
if !ok {
|
||||
diags.AddError(
|
||||
"Semantic Equality Check Error",
|
||||
"An unexpected value type was received while performing semantic equality checks. "+
|
||||
"Please report this to the provider developers.\n\n"+
|
||||
"Expected Value Type: "+fmt.Sprintf("%T", v)+"\n"+
|
||||
"Got Value Type: "+fmt.Sprintf("%T", newValuable),
|
||||
)
|
||||
|
||||
return false, diags
|
||||
}
|
||||
|
||||
priorString := strings.TrimSpace(v.StringValue.ValueString())
|
||||
newString := strings.TrimSpace(newValue.ValueString())
|
||||
|
||||
// If the strings are equivalent, keep the prior value
|
||||
return priorString == newString, diags
|
||||
}
|
||||
|
||||
// PlanModifier
|
||||
var _ planmodifier.String = RequiresReplaceForTrimmedStringModifier{}
|
||||
|
||||
type RequiresReplaceForTrimmedStringModifier struct{}
|
||||
|
||||
func (m RequiresReplaceForTrimmedStringModifier) Description(_ context.Context) string {
|
||||
return "If the value of this attribute changes, Terraform will destroy and recreate the resource."
|
||||
}
|
||||
|
||||
func (m RequiresReplaceForTrimmedStringModifier) MarkdownDescription(_ context.Context) string {
|
||||
return "If the value of this attribute changes, Terraform will destroy and recreate the resource."
|
||||
}
|
||||
|
||||
func (m RequiresReplaceForTrimmedStringModifier) PlanModifyString(ctx context.Context, req planmodifier.StringRequest, resp *planmodifier.StringResponse) {
|
||||
// Do not replace on resource creation.
|
||||
if req.State.Raw.IsNull() {
|
||||
return
|
||||
}
|
||||
// Do not replace on resource destroy.
|
||||
if req.Plan.Raw.IsNull() {
|
||||
return
|
||||
}
|
||||
// Do not replace if the plan and state values are equal.
|
||||
if req.PlanValue.Equal(req.StateValue) {
|
||||
return
|
||||
}
|
||||
|
||||
// Create Normalized values for the state and plan.
|
||||
stateNormalized := TrimmedStringValue{
|
||||
StringValue: req.StateValue,
|
||||
}
|
||||
planNormalized := TrimmedStringValue{
|
||||
StringValue: req.PlanValue,
|
||||
}
|
||||
|
||||
// Perform semantic equality check.
|
||||
semanticallyEqual, diags := stateNormalized.StringSemanticEquals(ctx, planNormalized)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if diags.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
if semanticallyEqual {
|
||||
tflog.Info(ctx, "Plan and state values are semantically equal. Suppressing differences.")
|
||||
resp.PlanValue = req.StateValue
|
||||
} else {
|
||||
resp.RequiresReplace = true
|
||||
}
|
||||
}
|
||||
+165
-116
@@ -32,129 +32,174 @@ func convertResourceSchemaToDataSourceSchema(rs r_schema.Schema, cfg AttributeCo
|
||||
|
||||
required := cfg.RequiredAttributes != nil && slices.Contains(*cfg.RequiredAttributes, name)
|
||||
optional := cfg.OptionalAttributes != nil && slices.Contains(*cfg.OptionalAttributes, name)
|
||||
switch attribute.GetType() {
|
||||
case types.BoolType:
|
||||
ds.Attributes[name] = d_schema.BoolAttribute{
|
||||
Description: attribute.GetDescription(),
|
||||
Required: required,
|
||||
Optional: optional,
|
||||
Computed: !required,
|
||||
Sensitive: attribute.IsSensitive(),
|
||||
MarkdownDescription: attribute.GetMarkdownDescription(),
|
||||
DeprecationMessage: attribute.GetDeprecationMessage(),
|
||||
}
|
||||
case types.DynamicType:
|
||||
ds.Attributes[name] = d_schema.DynamicAttribute{
|
||||
Description: attribute.GetDescription(),
|
||||
Required: required,
|
||||
Optional: optional,
|
||||
Computed: !required,
|
||||
Sensitive: attribute.IsSensitive(),
|
||||
MarkdownDescription: attribute.GetMarkdownDescription(),
|
||||
DeprecationMessage: attribute.GetDeprecationMessage(),
|
||||
}
|
||||
case types.Float32Type:
|
||||
ds.Attributes[name] = d_schema.Float32Attribute{
|
||||
Description: attribute.GetDescription(),
|
||||
Required: required,
|
||||
Optional: optional,
|
||||
Computed: !required,
|
||||
Sensitive: attribute.IsSensitive(),
|
||||
MarkdownDescription: attribute.GetMarkdownDescription(),
|
||||
DeprecationMessage: attribute.GetDeprecationMessage(),
|
||||
}
|
||||
case types.Float64Type:
|
||||
ds.Attributes[name] = d_schema.Float64Attribute{
|
||||
Description: attribute.GetDescription(),
|
||||
Required: required,
|
||||
Optional: optional,
|
||||
Computed: !required,
|
||||
Sensitive: attribute.IsSensitive(),
|
||||
MarkdownDescription: attribute.GetMarkdownDescription(),
|
||||
DeprecationMessage: attribute.GetDeprecationMessage(),
|
||||
}
|
||||
case types.Int32Type:
|
||||
ds.Attributes[name] = d_schema.Int32Attribute{
|
||||
Description: attribute.GetDescription(),
|
||||
Required: required,
|
||||
Optional: optional,
|
||||
Computed: !required,
|
||||
Sensitive: attribute.IsSensitive(),
|
||||
MarkdownDescription: attribute.GetMarkdownDescription(),
|
||||
DeprecationMessage: attribute.GetDeprecationMessage(),
|
||||
}
|
||||
case types.Int64Type:
|
||||
ds.Attributes[name] = d_schema.Int64Attribute{
|
||||
Description: attribute.GetDescription(),
|
||||
Required: required,
|
||||
Optional: optional,
|
||||
Computed: !required,
|
||||
Sensitive: attribute.IsSensitive(),
|
||||
MarkdownDescription: attribute.GetMarkdownDescription(),
|
||||
DeprecationMessage: attribute.GetDeprecationMessage(),
|
||||
}
|
||||
case types.NumberType:
|
||||
ds.Attributes[name] = d_schema.NumberAttribute{
|
||||
Description: attribute.GetDescription(),
|
||||
Required: required,
|
||||
Optional: optional,
|
||||
Computed: !required,
|
||||
Sensitive: attribute.IsSensitive(),
|
||||
MarkdownDescription: attribute.GetMarkdownDescription(),
|
||||
DeprecationMessage: attribute.GetDeprecationMessage(),
|
||||
}
|
||||
case types.StringType:
|
||||
ds.Attributes[name] = d_schema.StringAttribute{
|
||||
Description: attribute.GetDescription(),
|
||||
Required: required,
|
||||
Optional: optional,
|
||||
Computed: !required,
|
||||
Sensitive: attribute.IsSensitive(),
|
||||
MarkdownDescription: attribute.GetMarkdownDescription(),
|
||||
DeprecationMessage: attribute.GetDeprecationMessage(),
|
||||
}
|
||||
default:
|
||||
if listType, isList := attribute.GetType().(types.ListType); isList {
|
||||
ds.Attributes[name] = d_schema.ListAttribute{
|
||||
ElementType: listType.ElemType,
|
||||
Description: attribute.GetDescription(),
|
||||
Required: required,
|
||||
Optional: optional,
|
||||
Computed: !required,
|
||||
Sensitive: attribute.IsSensitive(),
|
||||
MarkdownDescription: attribute.GetMarkdownDescription(),
|
||||
DeprecationMessage: attribute.GetDeprecationMessage(),
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if objType, isObject := attribute.(r_schema.SingleNestedAttribute); isObject {
|
||||
attributeTypes := make(map[string]attr.Type, len(objType.GetAttributes()))
|
||||
for name, attribute := range objType.GetAttributes() {
|
||||
attributeTypes[name] = attribute.GetType()
|
||||
}
|
||||
|
||||
ds.Attributes[name] = d_schema.ObjectAttribute{
|
||||
CustomType: objType.CustomType,
|
||||
Description: attribute.GetDescription(),
|
||||
Required: required,
|
||||
Optional: optional,
|
||||
Computed: !required,
|
||||
Sensitive: attribute.IsSensitive(),
|
||||
MarkdownDescription: attribute.GetMarkdownDescription(),
|
||||
DeprecationMessage: attribute.GetDeprecationMessage(),
|
||||
AttributeTypes: attributeTypes,
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("failed to convert resource schema attribute to data source schema attribute: name=%s, type=%s", name, attribute.GetType())
|
||||
attr, err := convertResourceAttrToDataSourceAttr(name, attribute, required, optional)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to convert resource schema attribute to data source schema attribute: %w", err)
|
||||
}
|
||||
ds.Attributes[name] = attr
|
||||
}
|
||||
|
||||
return &ds, nil
|
||||
}
|
||||
|
||||
func convertResourceAttrToDataSourceAttr(name string, attribute r_schema.Attribute, required, optional bool) (d_schema.Attribute, error) {
|
||||
switch attribute.GetType() {
|
||||
case types.BoolType:
|
||||
return d_schema.BoolAttribute{
|
||||
Description: attribute.GetDescription(),
|
||||
Required: required,
|
||||
Optional: optional,
|
||||
Computed: !required,
|
||||
Sensitive: attribute.IsSensitive(),
|
||||
MarkdownDescription: attribute.GetMarkdownDescription(),
|
||||
DeprecationMessage: attribute.GetDeprecationMessage(),
|
||||
}, nil
|
||||
case types.DynamicType:
|
||||
return d_schema.DynamicAttribute{
|
||||
Description: attribute.GetDescription(),
|
||||
Required: required,
|
||||
Optional: optional,
|
||||
Computed: !required,
|
||||
Sensitive: attribute.IsSensitive(),
|
||||
MarkdownDescription: attribute.GetMarkdownDescription(),
|
||||
DeprecationMessage: attribute.GetDeprecationMessage(),
|
||||
}, nil
|
||||
case types.Float32Type:
|
||||
return d_schema.Float32Attribute{
|
||||
Description: attribute.GetDescription(),
|
||||
Required: required,
|
||||
Optional: optional,
|
||||
Computed: !required,
|
||||
Sensitive: attribute.IsSensitive(),
|
||||
MarkdownDescription: attribute.GetMarkdownDescription(),
|
||||
DeprecationMessage: attribute.GetDeprecationMessage(),
|
||||
}, nil
|
||||
case types.Float64Type:
|
||||
return d_schema.Float64Attribute{
|
||||
Description: attribute.GetDescription(),
|
||||
Required: required,
|
||||
Optional: optional,
|
||||
Computed: !required,
|
||||
Sensitive: attribute.IsSensitive(),
|
||||
MarkdownDescription: attribute.GetMarkdownDescription(),
|
||||
DeprecationMessage: attribute.GetDeprecationMessage(),
|
||||
}, nil
|
||||
case types.Int32Type:
|
||||
return d_schema.Int32Attribute{
|
||||
Description: attribute.GetDescription(),
|
||||
Required: required,
|
||||
Optional: optional,
|
||||
Computed: !required,
|
||||
Sensitive: attribute.IsSensitive(),
|
||||
MarkdownDescription: attribute.GetMarkdownDescription(),
|
||||
DeprecationMessage: attribute.GetDeprecationMessage(),
|
||||
}, nil
|
||||
case types.Int64Type:
|
||||
return d_schema.Int64Attribute{
|
||||
Description: attribute.GetDescription(),
|
||||
Required: required,
|
||||
Optional: optional,
|
||||
Computed: !required,
|
||||
Sensitive: attribute.IsSensitive(),
|
||||
MarkdownDescription: attribute.GetMarkdownDescription(),
|
||||
DeprecationMessage: attribute.GetDeprecationMessage(),
|
||||
}, nil
|
||||
case types.NumberType:
|
||||
return d_schema.NumberAttribute{
|
||||
Description: attribute.GetDescription(),
|
||||
Required: required,
|
||||
Optional: optional,
|
||||
Computed: !required,
|
||||
Sensitive: attribute.IsSensitive(),
|
||||
MarkdownDescription: attribute.GetMarkdownDescription(),
|
||||
DeprecationMessage: attribute.GetDeprecationMessage(),
|
||||
}, nil
|
||||
case types.StringType:
|
||||
return d_schema.StringAttribute{
|
||||
Description: attribute.GetDescription(),
|
||||
Required: required,
|
||||
Optional: optional,
|
||||
Computed: !required,
|
||||
Sensitive: attribute.IsSensitive(),
|
||||
MarkdownDescription: attribute.GetMarkdownDescription(),
|
||||
DeprecationMessage: attribute.GetDeprecationMessage(),
|
||||
}, nil
|
||||
|
||||
default:
|
||||
if t, isList := attribute.(r_schema.ListNestedAttribute); isList {
|
||||
nestedObjectAttrs := make(map[string]d_schema.Attribute)
|
||||
for name, attribute := range t.NestedObject.Attributes {
|
||||
nestedAttribute, err := convertResourceAttrToDataSourceAttr(name, attribute, required, optional)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nestedObjectAttrs[name] = nestedAttribute
|
||||
}
|
||||
return d_schema.ListNestedAttribute{
|
||||
NestedObject: d_schema.NestedAttributeObject{
|
||||
Attributes: nestedObjectAttrs,
|
||||
CustomType: t.NestedObject.CustomType,
|
||||
Validators: t.NestedObject.Validators,
|
||||
},
|
||||
CustomType: t.CustomType,
|
||||
Description: attribute.GetDescription(),
|
||||
Required: required,
|
||||
Optional: optional,
|
||||
Computed: !required,
|
||||
Sensitive: attribute.IsSensitive(),
|
||||
MarkdownDescription: attribute.GetMarkdownDescription(),
|
||||
DeprecationMessage: attribute.GetDeprecationMessage(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
if t, isList := attribute.GetType().(types.ListType); isList {
|
||||
return d_schema.ListAttribute{
|
||||
ElementType: t.ElemType,
|
||||
Description: attribute.GetDescription(),
|
||||
Required: required,
|
||||
Optional: optional,
|
||||
Computed: !required,
|
||||
Sensitive: attribute.IsSensitive(),
|
||||
MarkdownDescription: attribute.GetMarkdownDescription(),
|
||||
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() {
|
||||
attributeTypes[name] = attribute.GetType()
|
||||
}
|
||||
|
||||
return d_schema.ObjectAttribute{
|
||||
CustomType: t.CustomType,
|
||||
Description: attribute.GetDescription(),
|
||||
Required: required,
|
||||
Optional: optional,
|
||||
Computed: !required,
|
||||
Sensitive: attribute.IsSensitive(),
|
||||
MarkdownDescription: attribute.GetMarkdownDescription(),
|
||||
DeprecationMessage: attribute.GetDeprecationMessage(),
|
||||
AttributeTypes: attributeTypes,
|
||||
}, 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())
|
||||
}
|
||||
}
|
||||
|
||||
func listContainsUnknown(ctx context.Context, list types.List) bool {
|
||||
// If the whole list is unknown, return true
|
||||
if list.IsUnknown() {
|
||||
@@ -177,3 +222,7 @@ func listContainsUnknown(ctx context.Context, list types.List) bool {
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func Pointer[T any](d T) *T {
|
||||
return &d
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
|
||||
)
|
||||
|
||||
var (
|
||||
_ validator.Int32 = &MultipleOfValidator{}
|
||||
)
|
||||
|
||||
type MultipleOfValidator struct {
|
||||
Multiple, RangeFrom, RangeTo int32
|
||||
}
|
||||
|
||||
func (v MultipleOfValidator) Description(ctx context.Context) string {
|
||||
if v.RangeFrom == 0 {
|
||||
return fmt.Sprintf(`must be a multiple of %d`, v.Multiple)
|
||||
}
|
||||
return fmt.Sprintf("when greater than %d, must be a multiple of %d", v.RangeFrom, v.Multiple)
|
||||
}
|
||||
|
||||
func (v MultipleOfValidator) MarkdownDescription(ctx context.Context) string {
|
||||
if v.RangeFrom == 0 {
|
||||
return fmt.Sprintf(`must be a multiple of %d`, v.Multiple)
|
||||
}
|
||||
return fmt.Sprintf("when greater than %d, must be a multiple of %d", v.RangeFrom, v.Multiple)
|
||||
}
|
||||
|
||||
func (v MultipleOfValidator) ValidateInt32(ctx context.Context, req validator.Int32Request, resp *validator.Int32Response) {
|
||||
if req.ConfigValue.IsUnknown() || req.ConfigValue.IsNull() {
|
||||
return
|
||||
}
|
||||
memory := req.ConfigValue.ValueInt32()
|
||||
|
||||
if memory%v.Multiple == 0 || v.RangeFrom != 0 && memory < v.RangeFrom || v.RangeTo != 0 && memory >= v.RangeTo {
|
||||
return
|
||||
}
|
||||
|
||||
if v.RangeFrom != 0 {
|
||||
resp.Diagnostics.AddAttributeError(
|
||||
req.Path,
|
||||
"Not a Multiple",
|
||||
fmt.Sprintf("if greater than %d, value must be a multiple of %d", v.RangeFrom, v.Multiple),
|
||||
)
|
||||
} else {
|
||||
resp.Diagnostics.AddAttributeError(
|
||||
req.Path,
|
||||
"Not a Multiple",
|
||||
fmt.Sprintf("value must be a multiple of %d", v.Multiple),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,9 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/path"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
"github.com/hashicorp/terraform-plugin-log/tflog"
|
||||
)
|
||||
@@ -60,7 +63,7 @@ func (r *vpcResource) Schema(ctx context.Context, req resource.SchemaRequest, re
|
||||
|
||||
// Overrides
|
||||
id := resp.Schema.Attributes["id"]
|
||||
resp.Schema.Attributes["id"] = &schema.Int64Attribute{
|
||||
resp.Schema.Attributes["id"] = schema.Int64Attribute{
|
||||
Description: id.GetDescription(),
|
||||
MarkdownDescription: id.GetMarkdownDescription(),
|
||||
// read only
|
||||
@@ -68,6 +71,19 @@ func (r *vpcResource) Schema(ctx context.Context, req resource.SchemaRequest, re
|
||||
Required: false,
|
||||
Computed: true,
|
||||
}
|
||||
|
||||
ipRange := resp.Schema.Attributes["ip_range"]
|
||||
resp.Schema.Attributes["ip_range"] = schema.StringAttribute{
|
||||
Description: ipRange.GetDescription(),
|
||||
MarkdownDescription: ipRange.GetMarkdownDescription(),
|
||||
Required: false,
|
||||
Computed: true,
|
||||
Optional: true,
|
||||
PlanModifiers: []planmodifier.String{
|
||||
stringplanmodifier.RequiresReplace(),
|
||||
},
|
||||
Default: stringdefault.StaticString("10.240.0.0/16"),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *vpcResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
|
||||
@@ -130,6 +146,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",
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"terraform-provider-binarylane/internal/resources"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework/datasource"
|
||||
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
|
||||
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -47,10 +47,23 @@ func (d *vpcRouteEntriesDataSource) Schema(ctx context.Context, req datasource.S
|
||||
|
||||
// Overrides
|
||||
vpcId := resp.Schema.Attributes["vpc_id"]
|
||||
resp.Schema.Attributes["vpc_id"] = &schema.Int64Attribute{
|
||||
resp.Schema.Attributes["vpc_id"] = schema.Int64Attribute{
|
||||
Description: vpcId.GetDescription(),
|
||||
MarkdownDescription: vpcId.GetMarkdownDescription(),
|
||||
Required: true, // VPC ID is required to define the route entries
|
||||
Required: true, // vpc_id is required to define the route entries
|
||||
}
|
||||
|
||||
vpcRouteEntries := resp.Schema.Attributes["route_entries"].(schema.ListNestedAttribute)
|
||||
vpcRouteEntriesDescription := "The route entries that control how network traffic is directed through the VPC environment."
|
||||
resp.Schema.Attributes["route_entries"] = schema.ListNestedAttribute{
|
||||
Description: vpcRouteEntriesDescription,
|
||||
NestedObject: schema.NestedAttributeObject{
|
||||
CustomType: vpcRouteEntries.NestedObject.CustomType,
|
||||
Attributes: vpcRouteEntries.NestedObject.Attributes,
|
||||
},
|
||||
CustomType: vpcRouteEntries.CustomType,
|
||||
Required: false,
|
||||
Computed: true,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 (
|
||||
@@ -47,10 +48,10 @@ func (r *vpcRouteEntriesResource) Schema(ctx context.Context, req resource.Schem
|
||||
|
||||
// Overrides
|
||||
vpcId := resp.Schema.Attributes["vpc_id"]
|
||||
resp.Schema.Attributes["vpc_id"] = &schema.Int64Attribute{
|
||||
resp.Schema.Attributes["vpc_id"] = schema.Int64Attribute{
|
||||
Description: vpcId.GetDescription(),
|
||||
MarkdownDescription: vpcId.GetMarkdownDescription(),
|
||||
Required: true, // VPC ID is required to define the route entries
|
||||
Required: true, // vpc_id is required to define the route entries
|
||||
Validators: []validator.Int64{
|
||||
int64validator.AtLeast(1),
|
||||
},
|
||||
@@ -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",
|
||||
@@ -240,10 +246,11 @@ func GetRouteEntriesState(ctx context.Context, routeEntries *[]binarylane.RouteE
|
||||
routeEntriesValue := resources.RouteEntriesValue{}
|
||||
var routeEntriesValues []resources.RouteEntriesValue
|
||||
|
||||
if *routeEntries == nil || len(*routeEntries) == 0 {
|
||||
if len(*routeEntries) == 0 {
|
||||
routeEntriesValues = []resources.RouteEntriesValue{}
|
||||
} else {
|
||||
for _, route := range *routeEntries {
|
||||
// TODO: This panics if invalid, should be handled better
|
||||
r := resources.NewRouteEntriesValueMust(routeEntriesValue.AttributeTypes(ctx), map[string]attr.Value{
|
||||
"description": types.StringValue(*route.Description),
|
||||
"destination": types.StringValue(*route.Destination),
|
||||
|
||||
@@ -26,8 +26,8 @@ func LoadBalancerResourceSchema(ctx context.Context) schema.Schema {
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"entry_protocol": schema.StringAttribute{
|
||||
Required: true,
|
||||
Description: "The protocol that traffic must match for this load balancer to forward traffic according to this rule.",
|
||||
MarkdownDescription: "The protocol that traffic must match for this load balancer to forward traffic according to this rule.",
|
||||
Description: "The protocol that traffic must match for this load balancer to forward traffic according to this rule.\n\n| Value | Description |\n| ----- | ----------- |\n| http | The load balancer will forward HTTP traffic that matches this rule. |\n| https | The load balancer will forward HTTPS traffic that matches this rule. |\n\n",
|
||||
MarkdownDescription: "The protocol that traffic must match for this load balancer to forward traffic according to this rule.\n\n| Value | Description |\n| ----- | ----------- |\n| http | The load balancer will forward HTTP traffic that matches this rule. |\n| https | The load balancer will forward HTTPS traffic that matches this rule. |\n\n",
|
||||
Validators: []validator.String{
|
||||
stringvalidator.OneOf(
|
||||
"http",
|
||||
@@ -61,8 +61,8 @@ func LoadBalancerResourceSchema(ctx context.Context) schema.Schema {
|
||||
"protocol": schema.StringAttribute{
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
Description: "Leave null to accept the default HTTP protocol.",
|
||||
MarkdownDescription: "Leave null to accept the default HTTP protocol.",
|
||||
Description: "Leave null to accept the default HTTP protocol.\n\n| Value | Description |\n| ----- | ----------- |\n| http | The health check will be performed via HTTP. |\n| https | The health check will be performed via HTTPS. |\n| both | The health check will be performed via both HTTP and HTTPS. Failing a health check on one protocol will remove the server from the pool of servers only for that protocol. |\n\n",
|
||||
MarkdownDescription: "Leave null to accept the default HTTP protocol.\n\n| Value | Description |\n| ----- | ----------- |\n| http | The health check will be performed via HTTP. |\n| https | The health check will be performed via HTTPS. |\n| both | The health check will be performed via both HTTP and HTTPS. Failing a health check on one protocol will remove the server from the pool of servers only for that protocol. |\n\n",
|
||||
},
|
||||
},
|
||||
CustomType: HealthCheckType{
|
||||
|
||||
@@ -26,8 +26,8 @@ func ServerFirewallRulesResourceSchema(ctx context.Context) schema.Schema {
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"action": schema.StringAttribute{
|
||||
Required: true,
|
||||
Description: "The action to take when there is a match on this rule.",
|
||||
MarkdownDescription: "The action to take when there is a match on this rule.",
|
||||
Description: "The action to take when there is a match on this rule.\n\n| Value | Description |\n| ----- | ----------- |\n| drop | Traffic matching this rule will be dropped. |\n| accept | Traffic matching this rule will be accepted. |\n\n",
|
||||
MarkdownDescription: "The action to take when there is a match on this rule.\n\n| Value | Description |\n| ----- | ----------- |\n| drop | Traffic matching this rule will be dropped. |\n| accept | Traffic matching this rule will be accepted. |\n\n",
|
||||
Validators: []validator.String{
|
||||
stringvalidator.OneOf(
|
||||
"drop",
|
||||
@@ -62,8 +62,8 @@ func ServerFirewallRulesResourceSchema(ctx context.Context) schema.Schema {
|
||||
},
|
||||
"protocol": schema.StringAttribute{
|
||||
Required: true,
|
||||
Description: "The protocol to match for this rule.",
|
||||
MarkdownDescription: "The protocol to match for this rule.",
|
||||
Description: "The protocol to match for this rule.\n\n| Value | Description |\n| ----- | ----------- |\n| all | This rule will match any protocol. |\n| icmp | This rule will match ICMP traffic only. |\n| tcp | This rule will match TCP traffic only. |\n| udp | This rule will match UDP traffic only. |\n\n",
|
||||
MarkdownDescription: "The protocol to match for this rule.\n\n| Value | Description |\n| ----- | ----------- |\n| all | This rule will match any protocol. |\n| icmp | This rule will match ICMP traffic only. |\n| tcp | This rule will match TCP traffic only. |\n| udp | This rule will match UDP traffic only. |\n\n",
|
||||
Validators: []validator.String{
|
||||
stringvalidator.OneOf(
|
||||
"all",
|
||||
|
||||
@@ -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,
|
||||
@@ -31,6 +105,12 @@ func ServerResourceSchema(ctx context.Context) schema.Schema {
|
||||
Description: "The slug of the selected operating system.",
|
||||
MarkdownDescription: "The slug of the selected operating system.",
|
||||
},
|
||||
"ipv6": schema.BoolAttribute{
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
Description: "If true this will enable IPv6 for this server.",
|
||||
MarkdownDescription: "If true this will enable IPv6 for this server.",
|
||||
},
|
||||
"name": schema.StringAttribute{
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
@@ -86,14 +166,835 @@ 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"`
|
||||
Ipv6 types.Bool `tfsdk:"ipv6"`
|
||||
Name types.String `tfsdk:"name"`
|
||||
PortBlocking types.Bool `tfsdk:"port_blocking"`
|
||||
Region types.String `tfsdk:"region"`
|
||||
Size types.String `tfsdk:"size"`
|
||||
SshKeys types.List `tfsdk:"ssh_keys"`
|
||||
UserData types.String `tfsdk:"user_data"`
|
||||
VpcId types.Int64 `tfsdk:"vpc_id"`
|
||||
}
|
||||
|
||||
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{},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,21 +34,12 @@ func SshKeyResourceSchema(ctx context.Context) schema.Schema {
|
||||
stringvalidator.LengthAtLeast(1),
|
||||
},
|
||||
},
|
||||
"public_key": schema.StringAttribute{
|
||||
Required: true,
|
||||
Description: "The public key in OpenSSH \"authorized_keys\" format.",
|
||||
MarkdownDescription: "The public key in OpenSSH \"authorized_keys\" format.",
|
||||
Validators: []validator.String{
|
||||
stringvalidator.LengthAtLeast(1),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type SshKeyModel struct {
|
||||
Default types.Bool `tfsdk:"default"`
|
||||
Id types.Int64 `tfsdk:"id"`
|
||||
Name types.String `tfsdk:"name"`
|
||||
PublicKey types.String `tfsdk:"public_key"`
|
||||
Default types.Bool `tfsdk:"default"`
|
||||
Id types.Int64 `tfsdk:"id"`
|
||||
Name types.String `tfsdk:"name"`
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,9 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# The current provider generator will generate duplicate `OptionsType`s, so we
|
||||
# need to fix that by replacing `"name": "options"` with `"name": "options1"`,
|
||||
# `"name": "options2"`, etc. in the provider_code_spec.json file.
|
||||
|
||||
sed -i '0,/"name": "options"/ s/"name": "options"/"name": "options1"/' provider_code_spec.json
|
||||
sed -i '0,/"name": "options"/ s/"name": "options"/"name": "options2"/' provider_code_spec.json
|
||||
sed -i '0,/"name": "options"/ s/"name": "options"/"name": "options3"/' provider_code_spec.json
|
||||
+786
-25
@@ -1,4 +1,699 @@
|
||||
{
|
||||
"datasources": [
|
||||
{
|
||||
"name": "images",
|
||||
"schema": {
|
||||
"attributes": [
|
||||
{
|
||||
"name": "type",
|
||||
"string": {
|
||||
"computed_optional_required": "computed_optional",
|
||||
"description": "Queries for distribution will include images that have pre-installed applications."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "images",
|
||||
"list_nested": {
|
||||
"computed_optional_required": "computed",
|
||||
"nested_object": {
|
||||
"attributes": [
|
||||
{
|
||||
"name": "backup_info",
|
||||
"single_nested": {
|
||||
"computed_optional_required": "computed",
|
||||
"attributes": [
|
||||
{
|
||||
"name": "backup_disks",
|
||||
"list_nested": {
|
||||
"computed_optional_required": "computed",
|
||||
"nested_object": {
|
||||
"attributes": [
|
||||
{
|
||||
"name": "description",
|
||||
"string": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "A description of this disk."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"int64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The ID of this backup disk."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "min_disk_size",
|
||||
"int64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "This is the minimum disk size in GB required to restore this disk image."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "size_gigabytes",
|
||||
"float64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "This is the compressed size of the disk image in GB."
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "A list of the individual disks that make up this backup."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "iso",
|
||||
"bool": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "If this is true the backup is an ISO image and cannot be restored or downloaded. ISO images may only be attached for use as a boot disk or an additional disk."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locked",
|
||||
"bool": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "If this is true the backup is locked and cannot be replaced."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "offsite",
|
||||
"bool": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "If this is true, an attempt to create an offsite copy was made. This does not mean that the offsite copy attempt was successful or that the copy still exists."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "server_id",
|
||||
"int64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The server ID that was used to create this backup."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "type",
|
||||
"string": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "\n| Value | Description |\n| ----- | ----------- |\n| daily | A backup which is scheduled to be taken each day. |\n| weekly | A backup which is scheduled to be taken each week. |\n| monthly | A backup which is scheduled to be taken each month. |\n| temporary | A backup which is created on demand and only retained for a maximum of seven days. |\n\n"
|
||||
}
|
||||
}
|
||||
],
|
||||
"description": "If this image is a backup, this object will provide further information."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "created_at",
|
||||
"string": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "If this is a backup image this is the date and time in ISO8601 format when the image was created."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "description",
|
||||
"string": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "A description that may provide further details or warnings about the image."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "distribution",
|
||||
"string": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "If this is an operating system image, this is the name of the distribution. If this is a backup image, this is the name of the distribution the server is using."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "distribution_info",
|
||||
"single_nested": {
|
||||
"computed_optional_required": "computed",
|
||||
"attributes": [
|
||||
{
|
||||
"name": "features",
|
||||
"list": {
|
||||
"computed_optional_required": "computed",
|
||||
"element_type": {
|
||||
"string": {}
|
||||
},
|
||||
"description": "Features supported by this distribution."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "image_id",
|
||||
"int64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "If this is a backup image, the operating system ID of the server at the time the backup was created."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "password_recovery",
|
||||
"string": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "Supported methods of password recovery.\n\n| Value | Description |\n| ----- | ----------- |\n| manual | Password must be reset manually using the recovery console and rescue disk. |\n| offline-clear | Password can be cleared for the admin/root user only. New password needs to be provided on login via the console (Requires restart). |\n| offline-change | Password can be reset and new credentials sent (Requires restart). |\n| online-change | Password may be reset without requiring a reboot via installed QEMU Guest Agent. |\n\n"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "remote_access_user",
|
||||
"string": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "User name to use when connecting via remote access (RDP or SSH)."
|
||||
}
|
||||
}
|
||||
],
|
||||
"description": "This object may provide further information about the distribution."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "distribution_surcharges",
|
||||
"single_nested": {
|
||||
"computed_optional_required": "computed",
|
||||
"attributes": [
|
||||
{
|
||||
"name": "surcharge_base_cost",
|
||||
"float64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The additional cost for using this operating system as the base image for a size."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "surcharge_min_vcpu",
|
||||
"int64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The minimum vcpu count for surcharge calculations."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "surcharge_per_memory_max_megabytes",
|
||||
"int64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The maximum memory in MB that counts towards the surcharge_per_memory_mb. Any memory above this cap does not attract the surcharge."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "surcharge_per_memory_megabyte",
|
||||
"float64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The additional cost per MB for using this operating system as the base image for a size."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "surcharge_per_vcpu",
|
||||
"float64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The additional cost per vcpu for using this operating system as the base image for a size."
|
||||
}
|
||||
}
|
||||
],
|
||||
"description": "If this is not null the use of this image may incur surcharges above the base cost of the server. All costs are in AU$."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "error_message",
|
||||
"string": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "If the image creation failed this may provide further information."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "full_name",
|
||||
"string": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "If this is an operating system image, this is the name and version of the distribution. If this is a backup image, this is the server hostname and label of the backup if it exists, otherwise it is the server hostname and UTC timestamp of the creation of the image."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"int64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The ID of this image."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "min_disk_size",
|
||||
"int64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "For a distribution image this is the minimum disk size in GB required to install the operating system. For a backup image this is the minimum total disk size in GB required to restore the backup."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "min_memory_megabytes",
|
||||
"int64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "This is minimum memory in MB necessary to support this operating system (or the base operating system for a backup image)."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"string": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "If this is an operating system image, this is the name of the operating system version. If this is a backup image, this is the label of the backup if it exists, otherwise it is the UTC timestamp of the creation of the image."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "public",
|
||||
"bool": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "A public image is available to all users. A private image is available only to the account that created the image."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "regions",
|
||||
"list": {
|
||||
"computed_optional_required": "computed",
|
||||
"element_type": {
|
||||
"string": {}
|
||||
},
|
||||
"description": "The slugs of the regions where the image is available for use."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "size_gigabytes",
|
||||
"float64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "For a distribution image this is the disk size used in GB by the operating system on initial install. For a backup image this is the size of the compressed backup image in GB."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "slug",
|
||||
"string": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "If this is an operating system image this is a slug which may be used as an alternative to the ID as a reference."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "status",
|
||||
"string": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "\n| Value | Description |\n| ----- | ----------- |\n| NEW | The image is new. |\n| available | The image is available for use. |\n| pending | The image is pending and is not yet available for use. |\n| deleted | The image has been deleted and is no longer available for use. |\n\n"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "type",
|
||||
"string": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "\n| Value | Description |\n| ----- | ----------- |\n| custom | An image uploaded by a user. |\n| snapshot | A snapshot. Snapshot creation is not currently supported so only distribution images will have this value. |\n| backup | A backup of a server. |\n\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "regions",
|
||||
"schema": {
|
||||
"attributes": [
|
||||
{
|
||||
"name": "regions",
|
||||
"list_nested": {
|
||||
"computed_optional_required": "computed",
|
||||
"nested_object": {
|
||||
"attributes": [
|
||||
{
|
||||
"name": "available",
|
||||
"bool": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "Whether this region is available for the allocation of new resources."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "features",
|
||||
"list": {
|
||||
"computed_optional_required": "computed",
|
||||
"element_type": {
|
||||
"string": {}
|
||||
},
|
||||
"description": "A list of features available for resources in this region."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"string": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The name of this region."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "name_servers",
|
||||
"list": {
|
||||
"computed_optional_required": "computed",
|
||||
"element_type": {
|
||||
"string": {}
|
||||
},
|
||||
"description": "A list of nameservers available for resources in this region."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sizes",
|
||||
"list": {
|
||||
"computed_optional_required": "computed",
|
||||
"element_type": {
|
||||
"string": {}
|
||||
},
|
||||
"description": "The slugs of the sizes available in this region."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "slug",
|
||||
"string": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The unique slug for this region."
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sizes",
|
||||
"schema": {
|
||||
"attributes": [
|
||||
{
|
||||
"name": "server_id",
|
||||
"int64": {
|
||||
"computed_optional_required": "computed_optional",
|
||||
"description": "If supplied only sizes available for a resize the specified server will be returned. This parameter is only available when authenticated."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "image",
|
||||
"string": {
|
||||
"computed_optional_required": "computed_optional",
|
||||
"description": "If null or not provided regions that support the size are included in the returned objects regardless of operating system. If this is provided it must be the id or slug of an operating system image and will cause only valid regions for the size and operating system to be included in the returned objects."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sizes",
|
||||
"list_nested": {
|
||||
"computed_optional_required": "computed",
|
||||
"nested_object": {
|
||||
"attributes": [
|
||||
{
|
||||
"name": "available",
|
||||
"bool": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "If this is false the size is not available for new servers."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "cpu_description",
|
||||
"string": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "A description of the CPU provided in this size."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "description",
|
||||
"string": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "A description of this size."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "disk",
|
||||
"int64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The included storage for this size in GB."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "excess_transfer_cost_per_gigabyte",
|
||||
"float64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The excess charged for any transfer above the included data transfer in AU$ per GB."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "memory",
|
||||
"int64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The included memory for this size in MB."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "options",
|
||||
"single_nested": {
|
||||
"computed_optional_required": "computed",
|
||||
"attributes": [
|
||||
{
|
||||
"name": "backups_cost_per_backup_per_gigabyte",
|
||||
"float64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The cost per GB of storage of each selected backup. See the API support document for how to calculate the final cost of backups based on the options selected."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "daily_backups",
|
||||
"int64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The number of daily backups included in the base size cost."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "discount_for_no_public_ipv4",
|
||||
"float64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "This is the discount (if any) that is applied if no public IPv4 addresses are selected."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "disk_cost_per_additional_gigabyte",
|
||||
"float64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The additional cost per GB per month for additional storage space."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "disk_max",
|
||||
"int64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The maximum storage in GB permitted on this size."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "disk_min",
|
||||
"int64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The minimum storage in GB permitted on this size."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ipv4_addresses_cost_per_address",
|
||||
"float64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The additional cost per public IPv4 address per month for additional IPv4 addresses."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ipv4_addresses_max",
|
||||
"int64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The maximum number of IPv4 addresses permitted on this size."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "memory_cost_per_additional_megabyte",
|
||||
"float64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The additional cost per MB per month for additional memory."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "memory_max",
|
||||
"int64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The maximum memory in MB permitted on this size."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "monthly_backups",
|
||||
"int64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The number of monthly backups included in the base size cost."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "offsite_backup_frequency_cost",
|
||||
"single_nested": {
|
||||
"computed_optional_required": "computed",
|
||||
"attributes": [
|
||||
{
|
||||
"name": "daily_per_gigabyte",
|
||||
"float64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The additional cost per GB per month for enabling daily offsite backups. Only the highest value of the daily, weekly and monthly is applied. See the API support document for how to calculate the final cost of backups based on the options selected."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "monthly_per_gigabyte",
|
||||
"float64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The additional cost per GB per month for enabling monthly offsite backups. Only the highest value of the daily, weekly and monthly is applied. See the API support document for how to calculate the final cost of backups based on the options selected."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "weekly_per_gigabyte",
|
||||
"float64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The additional cost per GB per month for enabling weekly offsite backups. Only the highest value of the daily, weekly and monthly is applied. See the API support document for how to calculate the final cost of backups based on the options selected."
|
||||
}
|
||||
}
|
||||
],
|
||||
"description": "The additional cost per GB of storage for enabling offsite backups based on highest frequency of backups currently enabled. All costs are in AU$."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "offsite_backups_cost_per_gigabyte",
|
||||
"float64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The additional cost per GB of storage for enabling offsite backups. See the API support document for how to calculate the final cost of backups based on the options selected."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "restricted_disk_values",
|
||||
"list": {
|
||||
"computed_optional_required": "computed",
|
||||
"element_type": {
|
||||
"int64": {}
|
||||
},
|
||||
"description": "If this is null the normal valid values in the documentation for SizeOptionsRequest are used, otherwise only these values (in GB) are permitted."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "transfer_cost_per_additional_gigabyte",
|
||||
"float64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The additional cost per GB per month for additional included transfer."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "transfer_max",
|
||||
"float64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The maximum transfer in TB permitted for this size."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "weekly_backups",
|
||||
"int64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The number of weekly backups included in the base size cost."
|
||||
}
|
||||
}
|
||||
],
|
||||
"description": "Available add-ons (optional features not included in the base price) for the size. All costs are in AU$ per month (pro-rated)."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "price_hourly",
|
||||
"float64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "Hourly price in AU$."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "price_monthly",
|
||||
"float64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "Monthly Price in AU$."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "regions",
|
||||
"list": {
|
||||
"computed_optional_required": "computed",
|
||||
"element_type": {
|
||||
"string": {}
|
||||
},
|
||||
"description": "A list of region slugs where this size is available regardless of stock.\nIf this a response to a query that included a selected operating system this response will only include regions where that operating system is available on this size,\notherwise not all regions listed will support all operating systems on this size."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "regions_out_of_stock",
|
||||
"list": {
|
||||
"computed_optional_required": "computed",
|
||||
"element_type": {
|
||||
"string": {}
|
||||
},
|
||||
"description": "A list of region slugs where the size is normally available but is currently not available due to lack of stock."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "size_type",
|
||||
"single_nested": {
|
||||
"computed_optional_required": "computed",
|
||||
"attributes": [
|
||||
{
|
||||
"name": "description",
|
||||
"string": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The description of this size type, generally used to indicate the intended use case for sizes of this type."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"string": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The name of this size type."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "slug",
|
||||
"string": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The slug of this size type."
|
||||
}
|
||||
}
|
||||
],
|
||||
"description": "The type of this size, generally used to differentiate sizes optimized for different usages."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "slug",
|
||||
"string": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The slug of this size."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "storage_description",
|
||||
"string": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "A description of the storage provided in this size."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "transfer",
|
||||
"float64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The included data transfer for this size in TB."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "vcpu_units",
|
||||
"string": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "This is the unit that the vcpus field counts, e.g. \"core\" or \"thread\"."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "vcpus",
|
||||
"int64": {
|
||||
"computed_optional_required": "computed",
|
||||
"description": "The count of virtual CPUs for this size. See vcpu_units for a description of how each virtual CPU maps to the underlying hardware."
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"provider": {
|
||||
"name": "binarylane"
|
||||
},
|
||||
@@ -17,7 +712,7 @@
|
||||
"name": "entry_protocol",
|
||||
"string": {
|
||||
"computed_optional_required": "required",
|
||||
"description": "The protocol that traffic must match for this load balancer to forward traffic according to this rule.",
|
||||
"description": "The protocol that traffic must match for this load balancer to forward traffic according to this rule.\n\n| Value | Description |\n| ----- | ----------- |\n| http | The load balancer will forward HTTP traffic that matches this rule. |\n| https | The load balancer will forward HTTPS traffic that matches this rule. |\n\n",
|
||||
"validators": [
|
||||
{
|
||||
"custom": {
|
||||
@@ -58,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/.?=&+%_-]*\"), \"\")"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -68,7 +763,7 @@
|
||||
"name": "protocol",
|
||||
"string": {
|
||||
"computed_optional_required": "computed_optional",
|
||||
"description": "Leave null to accept the default HTTP protocol."
|
||||
"description": "Leave null to accept the default HTTP protocol.\n\n| Value | Description |\n| ----- | ----------- |\n| http | The health check will be performed via HTTP. |\n| https | The health check will be performed via HTTPS. |\n| both | The health check will be performed via both HTTP and HTTPS. Failing a health check on one protocol will remove the server from the pool of servers only for that protocol. |\n\n"
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -139,6 +834,13 @@
|
||||
"description": "The slug of the selected operating system."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ipv6",
|
||||
"bool": {
|
||||
"computed_optional_required": "computed_optional",
|
||||
"description": "If true this will enable IPv6 for this server."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"string": {
|
||||
@@ -233,6 +935,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."
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -251,7 +1031,7 @@
|
||||
"name": "action",
|
||||
"string": {
|
||||
"computed_optional_required": "required",
|
||||
"description": "The action to take when there is a match on this rule.",
|
||||
"description": "The action to take when there is a match on this rule.\n\n| Value | Description |\n| ----- | ----------- |\n| drop | Traffic matching this rule will be dropped. |\n| accept | Traffic matching this rule will be accepted. |\n\n",
|
||||
"validators": [
|
||||
{
|
||||
"custom": {
|
||||
@@ -321,7 +1101,7 @@
|
||||
"name": "protocol",
|
||||
"string": {
|
||||
"computed_optional_required": "required",
|
||||
"description": "The protocol to match for this rule.",
|
||||
"description": "The protocol to match for this rule.\n\n| Value | Description |\n| ----- | ----------- |\n| all | This rule will match any protocol. |\n| icmp | This rule will match ICMP traffic only. |\n| tcp | This rule will match TCP traffic only. |\n| udp | This rule will match UDP traffic only. |\n\n",
|
||||
"validators": [
|
||||
{
|
||||
"custom": {
|
||||
@@ -403,25 +1183,6 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "public_key",
|
||||
"string": {
|
||||
"computed_optional_required": "required",
|
||||
"description": "The public key in OpenSSH \"authorized_keys\" format.",
|
||||
"validators": [
|
||||
{
|
||||
"custom": {
|
||||
"imports": [
|
||||
{
|
||||
"path": "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
|
||||
}
|
||||
],
|
||||
"schema_definition": "stringvalidator.LengthAtLeast(1)"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"int64": {
|
||||
@@ -556,4 +1317,4 @@
|
||||
}
|
||||
],
|
||||
"version": "0.1"
|
||||
}
|
||||
}
|
||||
|
||||
+33
-3
@@ -40,7 +40,6 @@ resources:
|
||||
default will be deployed (assuming the operating system supports SSH Keys). Submit an empty list to
|
||||
disable deployment of default keys.
|
||||
ignores:
|
||||
- ipv6
|
||||
- licenses
|
||||
- links
|
||||
- server
|
||||
@@ -99,6 +98,7 @@ resources:
|
||||
key_id: id
|
||||
ignores:
|
||||
- ssh_key
|
||||
- public_key
|
||||
vpc:
|
||||
create:
|
||||
path: /vpcs
|
||||
@@ -136,5 +136,35 @@ resources:
|
||||
ignores:
|
||||
- name
|
||||
- vpc
|
||||
# data_sources:
|
||||
# Currently, don't need to generate data sources as they use the same schema as resources
|
||||
data_sources:
|
||||
images:
|
||||
read:
|
||||
path: /images
|
||||
method: GET
|
||||
schema:
|
||||
ignores:
|
||||
- links
|
||||
- meta
|
||||
- page
|
||||
- per_page
|
||||
- private
|
||||
regions:
|
||||
read:
|
||||
path: /regions
|
||||
method: GET
|
||||
schema:
|
||||
ignores:
|
||||
- links
|
||||
- meta
|
||||
- page
|
||||
- per_page
|
||||
sizes:
|
||||
read:
|
||||
path: /sizes
|
||||
method: GET
|
||||
schema:
|
||||
ignores:
|
||||
- links
|
||||
- meta
|
||||
- page
|
||||
- per_page
|
||||
|
||||
@@ -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."
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user