Files
terraform-provider-binarylane/provider_code_spec.json
T
Oscar Hermoso 725fa71248 💽 Add disks attribute to server resource & data source
Adds `disks` to `binarylane_server` and its data source, so a server's storage
can be split across several disks. Leave it unset and Binary Lane keeps managing
a single disk sized by `disk`; set it and it must describe every disk, including
the primary.

- The schema is generated the same way as `advanced_features`:
  scripts/data/server_disks.json is spliced into provider_code_spec.json by
  extend-provider.sh, with the list validator in
  internal/resources/server_disks_validators.go.
- `disk` remains the server's total storage. sum(disks[*].size_gigabytes) cannot
  exceed it, and any remainder is left unallocated.
- Create carves the additional disks out of the primary, which Binary Lane sizes
  to the whole total. Update frees space before the server's resize action and
  claims it afterwards, persisting what was actually done if a step fails.
- Disks are matched across plans by description, or by being the primary, and are
  numbered within a description so a server can have two disks sharing one.
- `disks` is returned in the order the configuration lists them, since Terraform
  requires a list's elements to stay where they were planned.
- Shrinking a disk warns at plan time, as does attaching additional disks
  alongside `user_data` that cloud-init may still be running.

Also bumps the OpenAPI schema to v0.39.2, and fixes two pre-existing bugs found
running the acceptance suite against real infrastructure: `advanced_features`
and `public_ipv6_addresses` weren't carried forward from state on a no-op
replan, so they planned as unknown on every apply.

🧪 Assert disks inline, and cover ordering in the acceptance tests

Drops the checkServerDisks/expectedDisk helper for the inline
TestCheckResourceAttr and TestCheckResourceAttrSet calls every other check in
this file uses.

Replaces the TestServerDisksToList unit test with the equivalent assertions in
TestServerResourceCreateWithDisks, which already reorders the disks of a real
server: the resource keeps the order its configuration lists them in, while the
data source, which has no order of its own, lists the primary disk first and the
rest by id. Both disks sharing the description "data" cover the duplicate case.

🧪 Pin disk ids across a list shift

Removing a disk shifts every disk after it down a position, which is where
terraform-plugin-framework#720 bites: Terraform merges prior state into the
proposed plan positionally, so the disk that moved up would inherit the id of
the one that was deleted, and the provider would resize the wrong disk.

planServerDisks matches by description (and by being the primary) instead of by
index, so this only asserts what should already hold: "alpha" and "beta" keep
the disks they had when "zeta" is removed from in front of them.

🏗️ Plan `disks` from a plan modifier on the attribute

Moves the planning of a configured `disks` out of the resource's ModifyPlan and
onto the attribute itself, as disksPlanModifier in internal/resources — the same
place, and declared the same way in scripts/data/server_disks.json, as
disksValidator.

Behaviour is unchanged: Terraform builds a list's proposed plan by merging prior
state in element by element, so removing a disk hands the disks after it the id
of their predecessor. The modifier plans the list from the configuration
instead, taking each disk's server-assigned values from the disk it matches in
prior state. DiskKey/DiskKeyer and DiskShrinkWarning move with it and are now
exported, since ordering and reconciliation match disks by the same rule.

What stays in ModifyPlan is the case `disks` is not configured, where what
happens to the disks depends on `disk` — the server's total, which ModifyPlan
resolves from state a few lines earlier, after attribute plan modifiers have
already run.

🏗️ Plan an unset `disks` on create from the plan modifier too

The creation case needs nothing but the absence of prior state, so it moves next
to the rest of the disk planning.

The remaining case — `disks` left out of the configuration on an existing server
— stays in ModifyPlan, and can't move: it depends on `disk`, the server's total,
which ModifyPlan resolves from state only after attribute plan modifiers have
run. Reading `disk` from the plan inside the modifier plans the disks as unknown
on every no-op replan, which TestServerResourceRename catches:

    ~ disks = [ - { id = 1 ... } ] -> (known after apply)
    Plan: 0 to add, 1 to change, 0 to destroy.

Working the total out from the configuration inside the modifier would restate a
rule that already lives in ModifyPlan, so it stays where the value it needs is.

🧪 Try `disks` as a SetNestedAttribute

A set has no order, so everything that existed to keep a list's elements where
Terraform planned them goes away: serverDisksToList's ranking and its `order`
argument threaded through five call sites become a three-line
types.SetValueFrom, and a configuration can list its disks however it likes.

Verified against the live API: create with duplicate descriptions, update
(resize, add, remove), dropping `disks`, reordering, and resizing one of two
disks that share a description — the case a set is least equipped for, since it
has no positions to match duplicates by.

Costs: a resize renders as a remove/add pair rather than an in-place change (the
id is preserved in both halves), and tests need checkDiskId to find a disk,
since a set has no index to address one with.

🪞 Reconcile disks as binarylane.Disk, not as Terraform values

binarylane.Disk carries tfsdk tags for exactly the attributes `disks` has, so a
configured set reflects straight into it. splitDisks now hands Create and Update
the API's own type, which is what the disks they compare against already are:
the comparison that read `disk.SizeGigabytes.ValueInt64() <
int64(other.SizeGigabytes)` now reads `disk.SizeGigabytes <
other.SizeGigabytes`. Eight value-unwrapping conversions go with it.

The plan modifier keeps building Terraform values by hand, since the attributes
Binary Lane assigns are still unknown while it runs.

🧪 Restore `disks` to ListNestedAttribute

Co-Authored-By: Marais Rossouw <maraisr@users.noreply.github.com>
2026-08-30 18:12:02 +08:00

1428 lines
51 KiB
JSON

{
"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. If this is the same as `transfer` no additional transfer is supported."
}
},
{
"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"
},
"resources": [
{
"name": "load_balancer",
"schema": {
"attributes": [
{
"name": "forwarding_rules",
"list_nested": {
"computed_optional_required": "computed_optional",
"nested_object": {
"attributes": [
{
"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.\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": {
"imports": [
{
"path": "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
}
],
"schema_definition": "stringvalidator.OneOf(\n\"http\",\n\"https\",\n)"
}
}
]
}
}
]
},
"description": "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."
}
},
{
"name": "health_check",
"single_nested": {
"computed_optional_required": "computed_optional",
"attributes": [
{
"name": "path",
"string": {
"computed_optional_required": "computed_optional",
"description": "Leave null to accept the default '/' path.",
"validators": [
{
"custom": {
"imports": [
{
"path": "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
}
],
"schema_definition": "stringvalidator.LengthAtLeast(1)"
}
},
{
"custom": {
"imports": [
{
"path": "regexp"
},
{
"path": "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
}
],
"schema_definition": "stringvalidator.RegexMatches(regexp.MustCompile(\"/[A-Za-z0-9/.?=&+%_-]*\"), \"\")"
}
}
]
}
},
{
"name": "protocol",
"string": {
"computed_optional_required": "computed_optional",
"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"
}
}
],
"description": "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."
}
},
{
"name": "name",
"string": {
"computed_optional_required": "required",
"description": "The hostname of the load balancer.",
"validators": [
{
"custom": {
"imports": [
{
"path": "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
}
],
"schema_definition": "stringvalidator.LengthAtLeast(1)"
}
}
]
}
},
{
"name": "region",
"string": {
"computed_optional_required": "computed_optional",
"description": "Leave null to create an anycast load balancer."
}
},
{
"name": "server_ids",
"set": {
"computed_optional_required": "computed_optional",
"element_type": {
"int64": {}
},
"description": "A list of server IDs to assign to this load balancer."
}
},
{
"name": "id",
"int64": {
"computed_optional_required": "computed_optional",
"description": "The ID of the load balancer to fetch."
}
}
]
}
},
{
"name": "server",
"schema": {
"attributes": [
{
"name": "backups",
"bool": {
"computed_optional_required": "computed_optional",
"description": "If true this will enable two daily backups for the server. `options.daily_backups` will override this value if provided. Setting this to false has no effect.\n"
}
},
{
"name": "image",
"string": {
"computed_optional_required": "required",
"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": {
"computed_optional_required": "computed_optional",
"description": "The hostname of your server, such as vps01.yourcompany.com. If not provided, the server will be created with a random name."
}
},
{
"name": "port_blocking",
"bool": {
"computed_optional_required": "computed_optional",
"description": "Port blocking of outgoing connections for email, SSH and Remote Desktop (TCP ports 22, 25, and 3389) is enabled by default for all new servers. If this is false port blocking will be disabled. Disabling port blocking is only available to verified accounts."
}
},
{
"name": "region",
"string": {
"computed_optional_required": "required",
"description": "The slug of the selected region.",
"validators": [
{
"custom": {
"imports": [
{
"path": "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
}
],
"schema_definition": "stringvalidator.LengthAtLeast(1)"
}
}
]
}
},
{
"name": "separate_private_network_interface",
"bool": {
"computed_optional_required": "computed_optional",
"description": "If true this will enable a separate private network interface for the server. This is only available for servers in a VPC."
}
},
{
"name": "size",
"string": {
"computed_optional_required": "required",
"description": "The slug of the selected size.",
"validators": [
{
"custom": {
"imports": [
{
"path": "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
}
],
"schema_definition": "stringvalidator.LengthAtLeast(1)"
}
}
]
}
},
{
"name": "ssh_keys",
"list": {
"computed_optional_required": "computed_optional",
"element_type": {
"int64": {}
},
"description": "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.\n"
}
},
{
"name": "user_data",
"string": {
"computed_optional_required": "computed_optional",
"description": "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.",
"validators": [
{
"custom": {
"imports": [
{
"path": "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
}
],
"schema_definition": "stringvalidator.LengthAtMost(65536)"
}
}
]
}
},
{
"name": "vpc_id",
"int64": {
"computed_optional_required": "computed_optional",
"description": "Leave null to use default (public) network for the selected region."
}
},
{
"name": "vpc_ipv4_address",
"string": {
"computed_optional_required": "computed_optional",
"description": "If provided this will be the Ipv4 address for the server's private VPC network adapter. If this is null an unused Ipv4 address will be assigned. This field is only valid when VpcId is provided."
}
},
{
"name": "id",
"int64": {
"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."
}
}
]
}
},
{
"name": "disks",
"list_nested": {
"computed_optional_required": "computed_optional",
"description": "The disks attached to this server. Leave null to let Binary Lane manage the server's disks. If specified, every disk must be listed, including the primary: exactly one entry must have `primary = true`, and its `id` and `description` are assigned by Binary Lane.",
"nested_object": {
"attributes": [
{
"name": "id",
"int64": {
"computed_optional_required": "computed",
"description": "The ID of this disk."
}
},
{
"name": "description",
"string": {
"computed_optional_required": "computed_optional",
"description": "A label for this disk. Assigned by Binary Lane for the primary disk, so must be left null when `primary = true`. Changing this will destroy the disk and create a new one, losing any data on it. Disks that share a description are matched in the order they are listed.",
"validators": [
{
"custom": {
"imports": [
{
"path": "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
}
],
"schema_definition": "stringvalidator.LengthAtLeast(1)"
}
}
]
}
},
{
"name": "primary",
"bool": {
"computed_optional_required": "computed_optional",
"description": "If `true` this is the primary disk, which the operating system is installed on. Exactly one disk must be the primary."
}
},
{
"name": "size_gigabytes",
"int64": {
"computed_optional_required": "required",
"description": "The size of the disk in GB. The sum across all disks cannot exceed `disk`, and any remainder is left unallocated.",
"validators": [
{
"custom": {
"imports": [
{
"path": "github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
}
],
"schema_definition": "int64validator.AtLeast(1)"
}
}
]
}
}
]
},
"validators": [
{
"custom": {
"schema_definition": "disksValidator{}"
}
}
],
"plan_modifiers": [
{
"custom": {
"imports": [
{
"path": "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
}
],
"schema_definition": "disksPlanModifier{}"
}
}
]
}
}
]
}
},
{
"name": "server_firewall_rules",
"schema": {
"attributes": [
{
"name": "firewall_rules",
"list_nested": {
"computed_optional_required": "required",
"nested_object": {
"attributes": [
{
"name": "action",
"string": {
"computed_optional_required": "required",
"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": {
"imports": [
{
"path": "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
}
],
"schema_definition": "stringvalidator.OneOf(\n\"drop\",\n\"accept\",\n)"
}
}
]
}
},
{
"name": "description",
"string": {
"computed_optional_required": "computed_optional",
"description": "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\".",
"validators": [
{
"custom": {
"imports": [
{
"path": "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
}
],
"schema_definition": "stringvalidator.LengthBetween(0, 250)"
}
}
]
}
},
{
"name": "destination_addresses",
"list": {
"computed_optional_required": "required",
"element_type": {
"string": {}
},
"description": "The destination addresses to match for this rule. Each address may be an individual IPv4 address or a range in IPv4 CIDR notation.",
"validators": [
{
"custom": {
"imports": [
{
"path": "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
}
],
"schema_definition": "listvalidator.SizeAtLeast(1)"
}
}
]
}
},
{
"name": "destination_ports",
"list": {
"computed_optional_required": "computed_optional",
"element_type": {
"string": {}
},
"description": "The destination ports to match for this rule. Leave null or empty to match on all ports."
}
},
{
"name": "protocol",
"string": {
"computed_optional_required": "required",
"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": {
"imports": [
{
"path": "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
}
],
"schema_definition": "stringvalidator.OneOf(\n\"all\",\n\"icmp\",\n\"tcp\",\n\"udp\",\n)"
}
}
]
}
},
{
"name": "source_addresses",
"list": {
"computed_optional_required": "required",
"element_type": {
"string": {}
},
"description": "The source addresses to match for this rule. Each address may be an individual IPv4 address or a range in IPv4 CIDR notation.",
"validators": [
{
"custom": {
"imports": [
{
"path": "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
}
],
"schema_definition": "listvalidator.SizeAtLeast(1)"
}
}
]
}
}
]
},
"description": "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."
}
},
{
"name": "server_id",
"int64": {
"computed_optional_required": "computed_optional",
"description": "The ID of the server for which firewall rules should be listed."
}
}
]
}
},
{
"name": "ssh_key",
"schema": {
"attributes": [
{
"name": "default",
"bool": {
"computed_optional_required": "computed_optional",
"description": "Optional: If true this will be added to all new server installations (if we support SSH Key injection for the server's operating system)."
}
},
{
"name": "name",
"string": {
"computed_optional_required": "required",
"description": "A name to help you identify the key.",
"validators": [
{
"custom": {
"imports": [
{
"path": "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
}
],
"schema_definition": "stringvalidator.LengthAtLeast(1)"
}
}
]
}
},
{
"name": "id",
"int64": {
"computed_optional_required": "computed_optional",
"description": "The ID or fingerprint of the SSH Key to fetch."
}
}
]
}
},
{
"name": "vpc",
"schema": {
"attributes": [
{
"name": "ip_range",
"string": {
"computed_optional_required": "computed_optional",
"description": "A private address range that you select during creation, such as the default value of 10.240.0.0/16. Because the virtual network is dedicated to your use, you may use whatever IP address range you like."
}
},
{
"name": "name",
"string": {
"computed_optional_required": "required",
"description": "A name to help identify this VPC.",
"validators": [
{
"custom": {
"imports": [
{
"path": "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
}
],
"schema_definition": "stringvalidator.LengthBetween(0, 250)"
}
}
]
}
},
{
"name": "id",
"int64": {
"computed_optional_required": "computed_optional",
"description": "The target vpc id."
}
}
]
}
},
{
"name": "vpc_route_entries",
"schema": {
"attributes": [
{
"name": "route_entries",
"list_nested": {
"computed_optional_required": "computed_optional",
"nested_object": {
"attributes": [
{
"name": "description",
"string": {
"computed_optional_required": "computed_optional",
"description": "An optional description for the route.",
"validators": [
{
"custom": {
"imports": [
{
"path": "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
}
],
"schema_definition": "stringvalidator.LengthAtMost(250)"
}
}
]
}
},
{
"name": "destination",
"string": {
"computed_optional_required": "required",
"description": "The destination address for this route entry. This may be in CIDR format.",
"validators": [
{
"custom": {
"imports": [
{
"path": "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
}
],
"schema_definition": "stringvalidator.LengthAtLeast(1)"
}
}
]
}
},
{
"name": "router",
"string": {
"computed_optional_required": "required",
"description": "The server that will receive traffic sent to the destination property in this VPC.",
"validators": [
{
"custom": {
"imports": [
{
"path": "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
}
],
"schema_definition": "stringvalidator.LengthAtLeast(1)"
}
}
]
}
}
]
},
"description": "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."
}
},
{
"name": "vpc_id",
"int64": {
"computed_optional_required": "computed_optional",
"description": "The target vpc id."
}
}
]
}
}
],
"version": "0.1",
"$schema": "https://raw.githubusercontent.com/hashicorp/terraform-plugin-codegen-spec/main/spec/v0.1/schema.json"
}