0
0
mirror of https://github.com/bpg/terraform-provider-proxmox.git synced 2025-06-29 18:21:10 +00:00

feat(vm): add network device resources (#376)

* wip

* experimenting with terraform plugin framework

* cleaning up poc and adding tests

* adding read / update / delete

* update bridge_vlan_aware and MTU

* add ipv6 and simplify IP support

* fix provider's schema

* add docs

* run linter from cmdline

* disable TF acceptance tests

* add VLAN

* update docs

* add examole

* cleanup
This commit is contained in:
Pavel Boldyrev 2023-06-23 18:47:25 -04:00 committed by GitHub
parent 2863aa6e2d
commit 343e8045c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
81 changed files with 3515 additions and 871 deletions

View File

@ -21,7 +21,5 @@ jobs:
with:
go-version-file: 'go.mod'
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: v1.52
only-new-issues: true
run: |
go run -modfile=tools/go.mod github.com/golangci/golangci-lint/cmd/golangci-lint run -v --timeout 5m

View File

@ -65,11 +65,15 @@ jobs:
- name: Get dependencies
run: go mod download
- name: TF acceptance tests
# - name: TF acceptance tests
# timeout-minutes: 10
# env:
# TF_ACC: "1"
# TF_ACC_TERRAFORM_VERSION: ${{ matrix.terraform }}
# run: go test -v -cover ./...
- name: Unit tests
timeout-minutes: 10
env:
TF_ACC: "1"
TF_ACC_TERRAFORM_VERSION: ${{ matrix.terraform }}
run: go test -v -cover ./...
all-tests-passed:

View File

@ -73,6 +73,7 @@ linters:
- funlen
- gocognit
# others
- depguard
- exhaustivestruct
- exhaustruct
- gci

View File

@ -35,7 +35,20 @@ We expect that all commit messages follow the
Please use the `scope` field to indicate the area of the codebase that is being
changed. For example, `vm` for changes in the Virtual Machine resource, or
`lcx` for changes in the Container resource:
`lcx` for changes in the Container resource.
Common scopes are:
- `vm` - Virtual Machine resources
- `lcx` - Container resources
- `provider` - Provider configuration and resources
- `core` - Core libraries and utilities
- `docs` - Documentation
- `ci` - Continuous Integration / Actions / GitHub Workflows
Please use lowercase for the description and do not end it with a period.
For example:
```
feat(vm): add support for the `clone` operation
@ -56,7 +69,7 @@ well.
We use automated release management orchestrated
by https://github.com/googleapis/release-please GitHub Action. The action
creates a new release PR with the changelog and bumps the version based on the
commit messages. The release PR is merged by the maintainers.
commit messages. The release PR is merged by the maintainers.
The release will be published to the GitHub Releases page and the Terraform
Registry.

View File

@ -0,0 +1,46 @@
---
layout: page
title: proxmox_virtual_environment_network_linux_bridge
permalink: /resources/virtual_environment_network_linux_bridge
nav_order: 13
parent: Resources
subcategory: Virtual Environment
---
# Resource: proxmox_virtual_environment_network_linux_bridge
Manages a Linux Bridge network interface in a Proxmox VE node.
## Example Usage
```terraform
resource "proxmox_virtual_environment_network_linux_bridge" "bridge99" {
node_name = "pve"
iface = "vmbr99"
address = "3.3.3.3/24"
comment = "created by terraform"
mtu = 1499
}
```
## Argument Reference
- `node_name` - (Required) The name of the node to manage the interface on.
- `name` - (Required) The interface name. Must be "vmbrN", where N is a number
between 0 and 9999.
- `address` - (Optional) The interface IPv4/CIDR address.
- `address6` - (Optional) The interface IPv6/CIDR address.
- `autostart` - (Optional) Automatically start interface on boot (defaults
to `true`).
- `ports` - (Optional) Specify the list of the interface bridge ports.
- `vlan_aware` - (Optional) Whether the interface bridge is VLAN aware (defaults
to `true`).
- `comment` - (Optional) Comment for the interface.
- `gateway` - (Optional) Default gateway address.
- `gateway6` - (Optional) Default IPv6 gateway address.
- `mtu` - (Optional) The interface MTU.
### Read-Only
- `id` (String) A unique identifier with format '<node name>:<iface>'

View File

@ -0,0 +1,43 @@
---
layout: page
title: proxmox_virtual_environment_network_linux_vlan
permalink: /resources/virtual_environment_network_linux_vlan
nav_order: 13
parent: Resources
subcategory: Virtual Environment
---
# Resource: proxmox_virtual_environment_network_linux_vlan
Manages a Linux VLAN network interface in a Proxmox VE node.
## Example Usage
```terraform
resource "proxmox_virtual_environment_network_linux_vlan" "vlan21" {
node_name = "pve"
iface = "ens18.21"
comment = "created by terraform"
}
```
## Argument Reference
- `node_name` - (Required) The name of the node to manage the interface on.
- `name` - (Required) The interface name. Add the VLAN tag number to an
existing interface name, e.g. "ens18.21".
- `address` - (Optional) The interface IPv4/CIDR address.
- `address6` - (Optional) The interface IPv6/CIDR address.
- `autostart` - (Optional) Automatically start interface on boot (defaults
to `true`).
- `comment` - (Optional) Comment for the interface.
- `gateway` - (Optional) Default gateway address.
- `gateway6` - (Optional) Default IPv6 gateway address.
- `mtu` - (Optional) The interface MTU.
### Read-Only
- `id` (String) A unique identifier with format '<node name>:<iface>'
- `interface` (String) The VLAN raw device.
- `vlan` (Number) The VLAN tag

View File

@ -1,7 +1,7 @@
data "proxmox_virtual_environment_vm" "example" {
depends_on = [proxmox_virtual_environment_vm.example]
vm_id = proxmox_virtual_environment_vm.example.vm_id
node_name = data.proxmox_virtual_environment_nodes.example.names[0]
vm_id = proxmox_virtual_environment_vm.example.vm_id
node_name = data.proxmox_virtual_environment_nodes.example.names[0]
}
output "proxmox_virtual_environment_vm_example" {

View File

@ -1,6 +1,6 @@
data "proxmox_virtual_environment_vms" "example" {
depends_on = [proxmox_virtual_environment_vm.example]
tags = ["ubuntu"]
tags = ["ubuntu"]
lifecycle {
postcondition {

View File

@ -18,8 +18,8 @@ resource "proxmox_virtual_environment_firewall_alias" "vm_alias" {
resource "proxmox_virtual_environment_firewall_alias" "container_alias" {
depends_on = [proxmox_virtual_environment_container.example]
node_name = proxmox_virtual_environment_container.example.node_name
container_id = proxmox_virtual_environment_container.example.vm_id
node_name = proxmox_virtual_environment_container.example.node_name
container_id = proxmox_virtual_environment_container.example.vm_id
name = "container-alias"
cidr = "192.168.2.0/23"

View File

@ -38,8 +38,8 @@ resource "proxmox_virtual_environment_firewall_ipset" "vm_ipset" {
resource "proxmox_virtual_environment_firewall_ipset" "container_ipset" {
depends_on = [proxmox_virtual_environment_container.example]
node_name = proxmox_virtual_environment_container.example.node_name
container_id = proxmox_virtual_environment_container.example.vm_id
node_name = proxmox_virtual_environment_container.example.node_name
container_id = proxmox_virtual_environment_container.example.vm_id
name = "container-ipset"
comment = "Managed by Terraform"

View File

@ -34,8 +34,8 @@ resource "proxmox_virtual_environment_firewall_options" "vm_options" {
resource "proxmox_virtual_environment_firewall_options" "container_options" {
depends_on = [proxmox_virtual_environment_container.example]
node_name = proxmox_virtual_environment_container.example.node_name
container_id = proxmox_virtual_environment_container.example.vm_id
node_name = proxmox_virtual_environment_container.example.node_name
container_id = proxmox_virtual_environment_container.example.vm_id
dhcp = false
enabled = false

View File

@ -58,8 +58,8 @@ resource "proxmox_virtual_environment_firewall_rules" "vm_rules" {
resource "proxmox_virtual_environment_firewall_rules" "container_rules" {
depends_on = [proxmox_virtual_environment_container.example]
node_name = proxmox_virtual_environment_container.example.node_name
container_id = proxmox_virtual_environment_container.example.vm_id
node_name = proxmox_virtual_environment_container.example.node_name
container_id = proxmox_virtual_environment_container.example.vm_id
rule {
type = "in"

View File

@ -0,0 +1,23 @@
resource "proxmox_virtual_environment_network_linux_vlan" "vlan99" {
node_name = "pve"
name = "ens18.99"
comment = "VLAN 99"
}
resource "proxmox_virtual_environment_network_linux_bridge" "vmbr99" {
depends_on = [
proxmox_virtual_environment_network_linux_vlan.vlan99
]
node_name = "pve"
name = "vmbr99"
address = "99.99.99.99/16"
comment = "vmbr99 comment"
ports = [
"ens18.99"
]
}

View File

@ -9,12 +9,12 @@ resource "proxmox_virtual_environment_vm" "example_template" {
description = "Managed by Terraform"
# disk {
# datastore_id = local.datastore_id
# file_id = proxmox_virtual_environment_file.ubuntu_cloud_image.id
# interface = "virtio0"
# iothread = true
# }
# disk {
# datastore_id = local.datastore_id
# file_id = proxmox_virtual_environment_file.ubuntu_cloud_image.id
# interface = "virtio0"
# iothread = true
# }
disk {
datastore_id = local.datastore_id
@ -24,12 +24,12 @@ resource "proxmox_virtual_environment_vm" "example_template" {
ssd = true
}
# disk {
# datastore_id = "nfs"
# interface = "scsi1"
# discard = "ignore"
# file_format = "raw"
# }
# disk {
# datastore_id = "nfs"
# interface = "scsi1"
# discard = "ignore"
# file_format = "raw"
# }
initialization {
datastore_id = local.datastore_id
@ -47,14 +47,14 @@ resource "proxmox_virtual_environment_vm" "example_template" {
#}
}
user_data_file_id = proxmox_virtual_environment_file.user_config.id
user_data_file_id = proxmox_virtual_environment_file.user_config.id
vendor_data_file_id = proxmox_virtual_environment_file.vendor_config.id
}
name = "terraform-provider-proxmox-example-template"
network_device {
mtu = 1450
mtu = 1450
}
network_device {
@ -81,7 +81,7 @@ resource "proxmox_virtual_environment_vm" "example" {
node_name = data.proxmox_virtual_environment_nodes.example.names[0]
pool_id = proxmox_virtual_environment_pool.example.id
vm_id = 2041
tags = ["terraform", "ubuntu"]
tags = ["terraform", "ubuntu"]
clone {
vm_id = proxmox_virtual_environment_vm.example_template.id
@ -105,13 +105,13 @@ resource "proxmox_virtual_environment_vm" "example" {
]
}
# While overwriting the initialization block when cloning a template is possible, it is not recommended.
# This will cause the coned VM to be reinitialized each time on re-apply.
# initialization {
# dns {
# server = "8.8.8.8"
# }
# }
# While overwriting the initialization block when cloning a template is possible, it is not recommended.
# This will cause the coned VM to be reinitialized each time on re-apply.
# initialization {
# dns {
# server = "8.8.8.8"
# }
# }
}

View File

@ -1,11 +1,11 @@
resource "local_sensitive_file" "example_ssh_private_key" {
filename = "${path.module}/autogenerated/id_rsa"
content = tls_private_key.example.private_key_pem
filename = "${path.module}/autogenerated/id_rsa"
content = tls_private_key.example.private_key_pem
}
resource "local_sensitive_file" "example_ssh_public_key" {
filename = "${path.module}/autogenerated/id_rsa.pub"
content = tls_private_key.example.public_key_openssh
filename = "${path.module}/autogenerated/id_rsa.pub"
content = tls_private_key.example.public_key_openssh
}
resource "tls_private_key" "example" {

View File

@ -9,7 +9,7 @@ terraform {
version = "3.1.0"
}
proxmox = {
source = "bpg/proxmox"
source = "bpg/proxmox"
}
}
}

31
go.mod
View File

@ -7,7 +7,11 @@ require (
github.com/google/uuid v1.3.0
github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320
github.com/hashicorp/go-multierror v1.1.1
github.com/hashicorp/terraform-plugin-framework v1.3.0
github.com/hashicorp/terraform-plugin-framework-validators v0.10.0
github.com/hashicorp/terraform-plugin-go v0.15.0
github.com/hashicorp/terraform-plugin-log v0.9.0
github.com/hashicorp/terraform-plugin-mux v0.10.0
github.com/hashicorp/terraform-plugin-sdk/v2 v2.26.1
github.com/pkg/sftp v1.13.5
github.com/skeema/knownhosts v1.1.1
@ -17,26 +21,31 @@ require (
)
require (
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect
github.com/agext/levenshtein v1.2.3 // indirect
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
github.com/cloudflare/circl v1.3.3 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fatih/color v1.14.1 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/go-cmp v0.5.9 // 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-hclog v1.5.0 // indirect
github.com/hashicorp/go-plugin v1.4.8 // indirect
github.com/hashicorp/go-plugin v1.4.9 // indirect
github.com/hashicorp/go-uuid v1.0.3 // indirect
github.com/hashicorp/go-version v1.6.0 // indirect
github.com/hashicorp/hc-install v0.5.2 // indirect
github.com/hashicorp/hcl/v2 v2.16.2 // indirect
github.com/hashicorp/logutils v1.0.0 // indirect
github.com/hashicorp/terraform-plugin-go v0.14.3 // indirect
github.com/hashicorp/terraform-registry-address v0.1.0 // indirect
github.com/hashicorp/terraform-exec v0.18.1 // indirect
github.com/hashicorp/terraform-json v0.16.0 // indirect
github.com/hashicorp/terraform-registry-address v0.2.0 // indirect
github.com/hashicorp/terraform-svchost v0.1.0 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect
github.com/kr/fs v0.1.0 // indirect
github.com/kr/pretty v0.2.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/kr/pretty v0.3.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
@ -47,16 +56,16 @@ require (
github.com/oklog/run v1.1.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
github.com/vmihailenco/msgpack/v4 v4.3.12 // indirect
github.com/vmihailenco/tagparser v0.1.2 // indirect
github.com/zclconf/go-cty v1.13.1 // indirect
github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
github.com/zclconf/go-cty v1.13.2 // indirect
golang.org/x/mod v0.10.0 // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/sys v0.9.0 // indirect
golang.org/x/text v0.10.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44 // indirect
google.golang.org/grpc v1.53.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
google.golang.org/grpc v1.54.0 // indirect
google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

105
go.sum
View File

@ -1,22 +1,30 @@
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 h1:wPbRQzjjwFc0ih8puEVAOFGELsn1zoIIYdxvML7mDxA=
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g=
github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ=
github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=
github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk=
github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec=
github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I=
github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs=
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
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=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w=
github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg=
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
github.com/go-git/go-billy/v5 v5.4.1 h1:Uwp5tDRkPr+l/TnbHOQzp+tmJfLceOlbVucgpTz8ix4=
github.com/go-git/go-git/v5 v5.6.1 h1:q4ZRqQl4pR/ZJHc1L5CFjGA1a10u76aV1iC+nh+bHsk=
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
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.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
@ -32,48 +40,65 @@ github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
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=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-checkpoint v0.5.0 h1:MFYpPZCnQqQTE18jFwSII6eUQrD/oxMFp3mlgcqk5mU=
github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuDrwkBuEQsVcpCOgg=
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-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c=
github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
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.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM=
github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s=
github.com/hashicorp/go-plugin v1.4.9 h1:ESiK220/qE0aGxWdzKIvRH69iLiuN/PjoLTm69RoWtU=
github.com/hashicorp/go-plugin v1.4.9/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/hc-install v0.5.2 h1:SfwMFnEXVVirpwkDuSF5kymUOhrUxrTq3udEseZdOD0=
github.com/hashicorp/hc-install v0.5.2/go.mod h1:9QISwe6newMWIfEiXpzuu1k9HAGtQYgnSH8H9T8wmoI=
github.com/hashicorp/hcl/v2 v2.16.2 h1:mpkHZh/Tv+xet3sy3F9Ld4FyI2tUpWe9x3XtPx9f1a0=
github.com/hashicorp/hcl/v2 v2.16.2/go.mod h1:JRmR89jycNkrrqnMmvPDMd56n1rQJ2Q6KocSLCMCXng=
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-plugin-go v0.14.3 h1:nlnJ1GXKdMwsC8g1Nh05tK2wsC3+3BL/DBBxFEki+j0=
github.com/hashicorp/terraform-plugin-go v0.14.3/go.mod h1:7ees7DMZ263q8wQ6E4RdIdR6nHHJtrdt4ogX5lPkX1A=
github.com/hashicorp/terraform-exec v0.18.1 h1:LAbfDvNQU1l0NOQlTuudjczVhHj061fNX5H8XZxHlH4=
github.com/hashicorp/terraform-exec v0.18.1/go.mod h1:58wg4IeuAJ6LVsLUeD2DWZZoc/bYi6dzhLHzxM41980=
github.com/hashicorp/terraform-json v0.16.0 h1:UKkeWRWb23do5LNAFlh/K3N0ymn1qTOO8c+85Albo3s=
github.com/hashicorp/terraform-json v0.16.0/go.mod h1:v0Ufk9jJnk6tcIZvScHvetlKfiNTC+WS21mnXIlc0B0=
github.com/hashicorp/terraform-plugin-framework v1.3.0 h1:WtP1CIaWAfbzME17xoUXvJcyh5Ewu9attdhbfWNnYLs=
github.com/hashicorp/terraform-plugin-framework v1.3.0/go.mod h1:A1WD3Ry7FhrThViUTbkx4ZDsMq9oaAv4U9oTI8bBzCU=
github.com/hashicorp/terraform-plugin-framework-validators v0.10.0 h1:4L0tmy/8esP6OcvocVymw52lY0HyQ5OxB7VNl7k4bS0=
github.com/hashicorp/terraform-plugin-framework-validators v0.10.0/go.mod h1:qdQJCdimB9JeX2YwOpItEu+IrfoJjWQ5PhLpAOMDQAE=
github.com/hashicorp/terraform-plugin-go v0.15.0 h1:1BJNSUFs09DS8h/XNyJNJaeusQuWc/T9V99ylU9Zwp0=
github.com/hashicorp/terraform-plugin-go v0.15.0/go.mod h1:tk9E3/Zx4RlF/9FdGAhwxHExqIHHldqiQGt20G6g+nQ=
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-mux v0.10.0 h1:VejY1BffxGy2iYOaa8DDHavY4k9jbvAE8F3lhruspKY=
github.com/hashicorp/terraform-plugin-mux v0.10.0/go.mod h1:9sdnpmY20xIsl4ItsfODZYE+MgpSy/osXpSf+RwaZCY=
github.com/hashicorp/terraform-plugin-sdk/v2 v2.26.1 h1:G9WAfb8LHeCxu7Ae8nc1agZlQOSCUWsb610iAogBhCs=
github.com/hashicorp/terraform-plugin-sdk/v2 v2.26.1/go.mod h1:xcOSYlRVdPLmDUoqPhO9fiO/YCN/l6MGYeTzGt5jgkQ=
github.com/hashicorp/terraform-registry-address v0.1.0 h1:W6JkV9wbum+m516rCl5/NjKxCyTVaaUBbzYcMzBDO3U=
github.com/hashicorp/terraform-registry-address v0.1.0/go.mod h1:EnyO2jYO6j29DTHbJcm00E5nQTFeTtyZH3H5ycydQ5A=
github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734/go.mod h1:kNDNcF7sN4DocDLBkQYz73HGKwN1ANB1blq4lIYLYvg=
github.com/hashicorp/terraform-registry-address v0.2.0 h1:92LUg03NhfgZv44zpNTLBGIbiyTokQCDcdH5BhVHT3s=
github.com/hashicorp/terraform-registry-address v0.2.0/go.mod h1:478wuzJPzdmqT6OGbB/iH82EDcI8VFM4yujknh/1nIs=
github.com/hashicorp/terraform-svchost v0.1.0 h1:0+RcgZdZYNd81Vw7tu62g9JiLLvbOigp7QtyNh6CjXk=
github.com/hashicorp/terraform-svchost v0.1.0/go.mod h1:ut8JaH0vumgdCfJaihdcZULqkAwHdQNwNH7taIDdsZM=
github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE=
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
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=
@ -96,13 +121,18 @@ github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zx
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
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/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
github.com/pkg/sftp v1.13.5 h1:a3RLUqkyjYRtBTZJZ1VRrKbN3zhuPLlUc3sphVz81go=
github.com/pkg/sftp v1.13.5/go.mod h1:wHDZ0IZX6JcBYRK1TH9bcVq8G7TLpVHYIGJRFnmPfxg=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
github.com/skeema/knownhosts v1.1.1 h1:MTk78x9FPgDFVFkDLTrsnnfCJl7g1C/nnKvePgrIngE=
github.com/skeema/knownhosts v1.1.1/go.mod h1:g4fPeYpque7P0xefxtGzV81ihjC8sX2IqpAoNkjxbMo=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
@ -110,34 +140,29 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl
github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
github.com/vmihailenco/msgpack/v4 v4.3.12 h1:07s4sz9IReOgdikxLTKNbBdqDMLsjPKXwvCazn8G65U=
github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
github.com/vmihailenco/tagparser v0.1.2 h1:gnjoVuB/kljJ5wICEEOpx98oXMWPLj22G67Vbd1qPqc=
github.com/vmihailenco/tagparser v0.1.2/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
github.com/zclconf/go-cty v1.1.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s=
github.com/zclconf/go-cty v1.13.1 h1:0a6bRwuiSHtAmqCqNOE+c2oHgepv0ctoxU4FUe43kwc=
github.com/zclconf/go-cty v1.13.1/go.mod h1:YKQzy/7pZ7iq2jNFzy5go57xdxdWoLLpaEp4u238AE0=
github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU=
github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc=
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
github.com/zclconf/go-cty v1.13.2 h1:4GvrUxe/QUDYuJKAav4EYqdM47/kZa672LwmXFmEKT0=
github.com/zclconf/go-cty v1.13.2/go.mod h1:YKQzy/7pZ7iq2jNFzy5go57xdxdWoLLpaEp4u238AE0=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0 h1:pVgRXcIictcr+lBQIFeiwuwtDIs4eL21OuM9nyAADmo=
golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20191009170851-d66e71096ffb/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -146,6 +171,7 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -162,22 +188,21 @@ golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44 h1:EfLuoKW5WfkgVdDy7dTK8qSbH37AX5mj/MFh+bGPz14=
google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44/go.mod h1:8B0gmkoRebU8ukX6HP+4wrVQUY1+6PkQ44BSyIlflHA=
google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc=
google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag=
google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=
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.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

8
internal/internal.go Normal file
View File

@ -0,0 +1,8 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
// Package internal contains implementation of the provider created with Terraform Plugin Framework.
package internal

View File

@ -0,0 +1,488 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package network
import (
"context"
"fmt"
"regexp"
"sort"
"strconv"
"strings"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/diag"
"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/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"
pvetypes "github.com/bpg/terraform-provider-proxmox/internal/types"
"github.com/bpg/terraform-provider-proxmox/proxmox"
"github.com/bpg/terraform-provider-proxmox/proxmox/nodes"
)
var (
_ resource.Resource = &linuxBridgeResource{}
_ resource.ResourceWithConfigure = &linuxBridgeResource{}
_ resource.ResourceWithImportState = &linuxBridgeResource{}
)
type linuxBridgeResourceModel struct {
// Base attributes
ID types.String `tfsdk:"id"`
NodeName types.String `tfsdk:"node_name"`
Name types.String `tfsdk:"name"`
Address pvetypes.IPCIDRValue `tfsdk:"address"`
Gateway pvetypes.IPAddrValue `tfsdk:"gateway"`
Address6 pvetypes.IPCIDRValue `tfsdk:"address6"`
Gateway6 pvetypes.IPAddrValue `tfsdk:"gateway6"`
Autostart types.Bool `tfsdk:"autostart"`
MTU types.Int64 `tfsdk:"mtu"`
Comment types.String `tfsdk:"comment"`
// Linux bridge attributes
Ports []types.String `tfsdk:"ports"`
VLANAware types.Bool `tfsdk:"vlan_aware"`
}
//nolint:lll
func (m *linuxBridgeResourceModel) exportToNetworkInterfaceCreateUpdateBody() *nodes.NetworkInterfaceCreateUpdateRequestBody {
body := &nodes.NetworkInterfaceCreateUpdateRequestBody{
Iface: m.Name.ValueString(),
Type: "bridge",
Autostart: pvetypes.CustomBool(m.Autostart.ValueBool()).Pointer(),
}
body.CIDR = m.Address.ValueStringPointer()
body.Gateway = m.Gateway.ValueStringPointer()
body.CIDR6 = m.Address6.ValueStringPointer()
body.Gateway6 = m.Gateway6.ValueStringPointer()
if !m.MTU.IsUnknown() {
body.MTU = m.MTU.ValueInt64Pointer()
}
body.Comments = m.Comment.ValueStringPointer()
var sanitizedPorts []string
for i := 0; i < len(m.Ports); i++ {
port := strings.TrimSpace(m.Ports[i].ValueString())
if len(port) > 0 {
sanitizedPorts = append(sanitizedPorts, port)
}
}
sort.Strings(sanitizedPorts)
bridgePorts := strings.Join(sanitizedPorts, " ")
if len(bridgePorts) > 0 {
body.BridgePorts = &bridgePorts
}
body.BridgeVLANAware = pvetypes.CustomBool(m.VLANAware.ValueBool()).Pointer()
return body
}
func (m *linuxBridgeResourceModel) importFromNetworkInterfaceList(
ctx context.Context,
iface *nodes.NetworkInterfaceListResponseData,
) error {
m.Address = pvetypes.NewIPCIDRPointerValue(iface.CIDR)
m.Gateway = pvetypes.NewIPAddrPointerValue(iface.Gateway)
m.Address6 = pvetypes.NewIPCIDRPointerValue(iface.CIDR6)
m.Gateway6 = pvetypes.NewIPAddrPointerValue(iface.Gateway6)
m.Autostart = types.BoolPointerValue(iface.Autostart.PointerBool())
if iface.MTU != nil {
if v, err := strconv.Atoi(*iface.MTU); err == nil {
m.MTU = types.Int64Value(int64(v))
}
} else {
m.MTU = types.Int64Null()
}
if iface.Comments != nil {
m.Comment = types.StringValue(strings.TrimSpace(*iface.Comments))
} else {
m.Comment = types.StringNull()
}
if iface.BridgeVLANAware != nil {
m.VLANAware = types.BoolPointerValue(iface.BridgeVLANAware.PointerBool())
} else {
m.VLANAware = types.BoolValue(false)
}
if iface.BridgePorts != nil && len(*iface.BridgePorts) > 0 {
ports, diags := types.ListValueFrom(ctx, types.StringType, strings.Split(*iface.BridgePorts, " "))
if diags.HasError() {
return fmt.Errorf("failed to parse bridge ports: %s", *iface.BridgePorts)
}
diags = ports.ElementsAs(ctx, &m.Ports, false)
if diags.HasError() {
return fmt.Errorf("failed to build bridge ports list: %s", *iface.BridgePorts)
}
}
return nil
}
// NewLinuxBridgeResource creates a new resource for managing Linux Bridge network interfaces.
func NewLinuxBridgeResource() resource.Resource {
return &linuxBridgeResource{}
}
type linuxBridgeResource struct {
client proxmox.Client
}
func (r *linuxBridgeResource) Metadata(
_ context.Context,
req resource.MetadataRequest,
resp *resource.MetadataResponse,
) {
resp.TypeName = req.ProviderTypeName + "_network_linux_bridge"
}
// Schema defines the schema for the resource.
func (r *linuxBridgeResource) Schema(
_ context.Context,
_ resource.SchemaRequest,
resp *resource.SchemaResponse,
) {
resp.Schema = schema.Schema{
Description: "Manages a Linux Bridge network interface in a Proxmox VE node.",
Attributes: map[string]schema.Attribute{
// Base attributes
"id": schema.StringAttribute{
Computed: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
Description: "A unique identifier with format '<node name>:<iface>'",
},
"node_name": schema.StringAttribute{
Description: "The name of the node.",
Required: true,
},
"name": schema.StringAttribute{
Description: "The interface name.",
Required: true,
Validators: []validator.String{
stringvalidator.RegexMatches(
regexp.MustCompile(`^vmbr(\d{1,4})$`),
`must be "vmbrN", where N is a number between 0 and 9999`,
),
},
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"address": schema.StringAttribute{
Description: "The interface IPv4/CIDR address.",
CustomType: pvetypes.IPCIDRType{},
Optional: true,
},
"gateway": schema.StringAttribute{
Description: "Default gateway address.",
CustomType: pvetypes.IPAddrType{},
Optional: true,
},
"address6": schema.StringAttribute{
Description: "The interface IPv6/CIDR address.",
CustomType: pvetypes.IPCIDRType{},
Optional: true,
},
"gateway6": schema.StringAttribute{
Description: "Default IPv6 gateway address.",
CustomType: pvetypes.IPAddrType{},
Optional: true,
},
"autostart": schema.BoolAttribute{
Description: "Automatically start interface on boot.",
Optional: true,
Computed: true,
Default: booldefault.StaticBool(true),
},
"mtu": schema.Int64Attribute{
Description: "The interface MTU.",
Optional: true,
Computed: true,
},
"comment": schema.StringAttribute{
Description: "Comment for the interface.",
Optional: true,
},
// Linux Bridge attributes
"ports": schema.ListAttribute{
Description: "The interface bridge ports.",
Optional: true,
ElementType: types.StringType,
},
"vlan_aware": schema.BoolAttribute{
Description: "Whether the interface bridge is VLAN aware.",
Optional: true,
Computed: true,
},
},
}
}
func (r *linuxBridgeResource) Configure(
_ context.Context,
req resource.ConfigureRequest,
resp *resource.ConfigureResponse,
) {
if req.ProviderData == nil {
return
}
client, ok := req.ProviderData.(proxmox.Client)
if !ok {
resp.Diagnostics.AddError(
"Unexpected Resource Configure Type",
fmt.Sprintf("Expected *proxmox.Client, got: %T. Please report this issue to the provider developers.",
req.ProviderData),
)
return
}
r.client = client
}
//nolint:dupl
func (r *linuxBridgeResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var plan linuxBridgeResourceModel
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
body := plan.exportToNetworkInterfaceCreateUpdateBody()
err := r.client.Node(plan.NodeName.ValueString()).CreateNetworkInterface(ctx, body)
if err != nil {
resp.Diagnostics.AddError(
"Error creating Linux Bridge interface",
"Could not create Linux Bridge, unexpected error: "+err.Error(),
)
return
}
plan.ID = types.StringValue(plan.NodeName.ValueString() + ":" + plan.Name.ValueString())
r.read(ctx, &plan, &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}
resp.State.Set(ctx, plan)
resp.Diagnostics.Append(diags...)
err = r.client.Node(plan.NodeName.ValueString()).ReloadNetworkConfiguration(ctx)
if err != nil {
resp.Diagnostics.AddError(
"Error reloading network configuration",
fmt.Sprintf("Could not reload network configuration on node '%s', unexpected error: %s",
plan.NodeName.ValueString(), err.Error()),
)
}
}
func (r *linuxBridgeResource) read(ctx context.Context, model *linuxBridgeResourceModel, diags *diag.Diagnostics) {
ifaces, err := r.client.Node(model.NodeName.ValueString()).ListNetworkInterfaces(ctx)
if err != nil {
diags.AddError(
"Error listing network interfaces",
"Could not list network interfaces, unexpected error: "+err.Error(),
)
return
}
for _, iface := range ifaces {
if iface.Iface != model.Name.ValueString() {
continue
}
err = model.importFromNetworkInterfaceList(ctx, iface)
if err != nil {
diags.AddError(
"Error converting network interface to a model",
"Could not import network interface from API response, unexpected error: "+err.Error(),
)
return
}
break
}
}
// Read reads a Linux Bridge interface.
func (r *linuxBridgeResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
// Get current state
var state linuxBridgeResourceModel
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
r.read(ctx, &state, &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, state)
resp.Diagnostics.Append(diags...)
}
// Update updates a Linux Bridge interface.
func (r *linuxBridgeResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var plan, state linuxBridgeResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}
body := plan.exportToNetworkInterfaceCreateUpdateBody()
var toDelete []string
if !plan.MTU.Equal(state.MTU) && (plan.MTU.IsUnknown() || plan.MTU.ValueInt64() == 0) {
toDelete = append(toDelete, "mtu")
body.MTU = nil
}
// VLANAware is computed, will never be null
if !plan.VLANAware.Equal(state.VLANAware) && !plan.VLANAware.ValueBool() {
toDelete = append(toDelete, "bridge_vlan_aware")
body.BridgeVLANAware = nil
}
if len(toDelete) > 0 {
body.Delete = &toDelete
}
err := r.client.Node(plan.NodeName.ValueString()).UpdateNetworkInterface(ctx, plan.Name.ValueString(), body)
if err != nil {
resp.Diagnostics.AddError(
"Error updating Linux Bridge interface",
"Could not update Linux Bridge, unexpected error: "+err.Error(),
)
return
}
r.read(ctx, &plan, &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}
resp.Diagnostics.Append(resp.State.Set(ctx, plan)...)
err = r.client.Node(state.NodeName.ValueString()).ReloadNetworkConfiguration(ctx)
if err != nil {
resp.Diagnostics.AddError(
"Error reloading network configuration",
fmt.Sprintf("Could not reload network configuration on node '%s', unexpected error: %s",
state.NodeName.ValueString(), err.Error()),
)
}
}
// Delete deletes a Linux Bridge interface.
//
//nolint:dupl
func (r *linuxBridgeResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var state linuxBridgeResourceModel
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
err := r.client.Node(state.NodeName.ValueString()).DeleteNetworkInterface(ctx, state.Name.ValueString())
if err != nil {
if strings.Contains(err.Error(), "interface does not exist") {
resp.Diagnostics.AddWarning(
"Linux Bridge interface does not exist",
fmt.Sprintf("Could not delete Linux Bridge '%s', interface does not exist, "+
"or has already been deleted outside of Terraform.", state.Name.ValueString()),
)
} else {
resp.Diagnostics.AddError(
"Error deleting Linux Bridge interface",
fmt.Sprintf("Could not delete Linux Bridge '%s', unexpected error: %s",
state.Name.ValueString(), err.Error()),
)
}
return
}
err = r.client.Node(state.NodeName.ValueString()).ReloadNetworkConfiguration(ctx)
if err != nil {
resp.Diagnostics.AddError(
"Error reloading network configuration",
fmt.Sprintf("Could not reload network configuration on node '%s', unexpected error: %s",
state.NodeName.ValueString(), err.Error()),
)
}
}
func (r *linuxBridgeResource) ImportState(
ctx context.Context,
req resource.ImportStateRequest,
resp *resource.ImportStateResponse,
) {
idParts := strings.Split(req.ID, ":")
if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" {
resp.Diagnostics.AddError(
"Unexpected Import Identifier",
fmt.Sprintf("Expected import identifier with format: node_name:iface. Got: %q", req.ID),
)
return
}
nodeName := idParts[0]
iface := idParts[1]
state := linuxBridgeResourceModel{
ID: types.StringValue(req.ID),
NodeName: types.StringValue(nodeName),
Name: types.StringValue(iface),
}
r.read(ctx, &state, &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}
diags := resp.State.Set(ctx, state)
resp.Diagnostics.Append(diags...)
}

View File

@ -0,0 +1,451 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package network
import (
"context"
"fmt"
"strconv"
"strings"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/diag"
"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/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"
pvetypes "github.com/bpg/terraform-provider-proxmox/internal/types"
"github.com/bpg/terraform-provider-proxmox/proxmox"
"github.com/bpg/terraform-provider-proxmox/proxmox/nodes"
)
var (
_ resource.Resource = &linuxVLANResource{}
_ resource.ResourceWithConfigure = &linuxVLANResource{}
_ resource.ResourceWithImportState = &linuxVLANResource{}
)
type linuxVLANResourceModel struct {
// Base attributes
ID types.String `tfsdk:"id"`
NodeName types.String `tfsdk:"node_name"`
Name types.String `tfsdk:"name"`
Address pvetypes.IPCIDRValue `tfsdk:"address"`
Gateway pvetypes.IPAddrValue `tfsdk:"gateway"`
Address6 pvetypes.IPCIDRValue `tfsdk:"address6"`
Gateway6 pvetypes.IPAddrValue `tfsdk:"gateway6"`
Autostart types.Bool `tfsdk:"autostart"`
MTU types.Int64 `tfsdk:"mtu"`
Comment types.String `tfsdk:"comment"`
// Linux VLAN attributes
Interface types.String `tfsdk:"interface"`
VLAN types.Int64 `tfsdk:"vlan"`
}
//nolint:lll
func (m *linuxVLANResourceModel) exportToNetworkInterfaceCreateUpdateBody() *nodes.NetworkInterfaceCreateUpdateRequestBody {
body := &nodes.NetworkInterfaceCreateUpdateRequestBody{
Iface: m.Name.ValueString(),
Type: "vlan",
Autostart: pvetypes.CustomBool(m.Autostart.ValueBool()).Pointer(),
}
body.CIDR = m.Address.ValueStringPointer()
body.Gateway = m.Gateway.ValueStringPointer()
body.CIDR6 = m.Address6.ValueStringPointer()
body.Gateway6 = m.Gateway6.ValueStringPointer()
body.Comments = m.Comment.ValueStringPointer()
if !m.MTU.IsUnknown() {
body.MTU = m.MTU.ValueInt64Pointer()
}
if !m.Interface.IsUnknown() {
body.VLANRawDevice = m.Interface.ValueStringPointer()
}
if !m.VLAN.IsUnknown() {
body.VLANID = m.VLAN.ValueInt64Pointer()
}
return body
}
func (m *linuxVLANResourceModel) importFromNetworkInterfaceList(iface *nodes.NetworkInterfaceListResponseData) {
m.Address = pvetypes.NewIPCIDRPointerValue(iface.CIDR)
m.Gateway = pvetypes.NewIPAddrPointerValue(iface.Gateway)
m.Address6 = pvetypes.NewIPCIDRPointerValue(iface.CIDR6)
m.Gateway6 = pvetypes.NewIPAddrPointerValue(iface.Gateway6)
m.Autostart = types.BoolPointerValue(iface.Autostart.PointerBool())
if iface.MTU != nil {
if v, err := strconv.Atoi(*iface.MTU); err == nil {
m.MTU = types.Int64Value(int64(v))
}
} else {
m.MTU = types.Int64Null()
}
if iface.Comments != nil {
m.Comment = types.StringValue(strings.TrimSpace(*iface.Comments))
} else {
m.Comment = types.StringNull()
}
if iface.VLANID != nil {
if v, err := strconv.Atoi(*iface.VLANID); err == nil {
m.VLAN = types.Int64Value(int64(v))
}
} else {
// in reality, this should never happen
m.VLAN = types.Int64Unknown()
}
if iface.VLANRawDevice != nil {
m.Interface = types.StringValue(strings.TrimSpace(*iface.VLANRawDevice))
} else {
m.Interface = types.StringNull()
}
}
// NewLinuxVLANResource creates a new resource for managing Linux VLAN network interfaces.
func NewLinuxVLANResource() resource.Resource {
return &linuxVLANResource{}
}
type linuxVLANResource struct {
client proxmox.Client
}
func (r *linuxVLANResource) Metadata(
_ context.Context,
req resource.MetadataRequest,
resp *resource.MetadataResponse,
) {
resp.TypeName = req.ProviderTypeName + "_network_linux_vlan"
}
// Schema defines the schema for the resource.
func (r *linuxVLANResource) Schema(
_ context.Context,
_ resource.SchemaRequest,
resp *resource.SchemaResponse,
) {
resp.Schema = schema.Schema{
Description: "Manages a Linux VLAN network interface in a Proxmox VE node.",
Attributes: map[string]schema.Attribute{
// Base attributes
"id": schema.StringAttribute{
Computed: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
Description: "A unique identifier with format '<node name>:<iface>'",
},
"node_name": schema.StringAttribute{
Description: "The name of the node.",
Required: true,
},
"name": schema.StringAttribute{
Description: "The interface name.",
Required: true,
Validators: []validator.String{
stringvalidator.LengthAtLeast(3),
},
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"address": schema.StringAttribute{
Description: "The interface IPv4/CIDR address.",
CustomType: pvetypes.IPCIDRType{},
Optional: true,
},
"gateway": schema.StringAttribute{
Description: "Default gateway address.",
CustomType: pvetypes.IPAddrType{},
Optional: true,
},
"address6": schema.StringAttribute{
Description: "The interface IPv6/CIDR address.",
CustomType: pvetypes.IPCIDRType{},
Optional: true,
},
"gateway6": schema.StringAttribute{
Description: "Default IPv6 gateway address.",
CustomType: pvetypes.IPAddrType{},
Optional: true,
},
"autostart": schema.BoolAttribute{
Description: "Automatically start interface on boot.",
Optional: true,
Computed: true,
Default: booldefault.StaticBool(true),
},
"mtu": schema.Int64Attribute{
Description: "The interface MTU.",
Optional: true,
Computed: true,
},
"comment": schema.StringAttribute{
Description: "Comment for the interface.",
Optional: true,
},
// Linux VLAN attributes
"interface": schema.StringAttribute{
// read-only
Description: "The VLAN raw device.",
Computed: true,
},
"vlan": schema.Int64Attribute{
// read-only
Description: "The VLAN tag",
Computed: true,
},
},
}
}
func (r *linuxVLANResource) Configure(
_ context.Context,
req resource.ConfigureRequest,
resp *resource.ConfigureResponse,
) {
if req.ProviderData == nil {
return
}
client, ok := req.ProviderData.(proxmox.Client)
if !ok {
resp.Diagnostics.AddError(
"Unexpected Resource Configure Type",
fmt.Sprintf("Expected *proxmox.Client, got: %T. Please report this issue to the provider developers.",
req.ProviderData),
)
return
}
r.client = client
}
//nolint:dupl
func (r *linuxVLANResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var plan linuxVLANResourceModel
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
body := plan.exportToNetworkInterfaceCreateUpdateBody()
err := r.client.Node(plan.NodeName.ValueString()).CreateNetworkInterface(ctx, body)
if err != nil {
resp.Diagnostics.AddError(
"Error creating Linux VLAN interface",
"Could not create Linux VLAN, unexpected error: "+err.Error(),
)
return
}
plan.ID = types.StringValue(plan.NodeName.ValueString() + ":" + plan.Name.ValueString())
r.read(ctx, &plan, &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}
resp.State.Set(ctx, plan)
resp.Diagnostics.Append(diags...)
err = r.client.Node(plan.NodeName.ValueString()).ReloadNetworkConfiguration(ctx)
if err != nil {
resp.Diagnostics.AddError(
"Error reloading network configuration",
fmt.Sprintf("Could not reload network configuration on node '%s', unexpected error: %s",
plan.NodeName.ValueString(), err.Error()),
)
}
}
func (r *linuxVLANResource) read(ctx context.Context, model *linuxVLANResourceModel, diags *diag.Diagnostics) {
ifaces, err := r.client.Node(model.NodeName.ValueString()).ListNetworkInterfaces(ctx)
if err != nil {
diags.AddError(
"Error listing network interfaces",
"Could not list network interfaces, unexpected error: "+err.Error(),
)
return
}
for _, iface := range ifaces {
if iface.Iface != model.Name.ValueString() {
continue
}
model.importFromNetworkInterfaceList(iface)
break
}
}
// Read reads a Linux VLAN interface.
func (r *linuxVLANResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
// Get current state
var state linuxVLANResourceModel
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
r.read(ctx, &state, &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, state)
resp.Diagnostics.Append(diags...)
}
// Update updates a Linux VLAN interface.
func (r *linuxVLANResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var plan, state linuxVLANResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}
body := plan.exportToNetworkInterfaceCreateUpdateBody()
var toDelete []string
if !plan.MTU.Equal(state.MTU) && (plan.MTU.IsUnknown() || plan.MTU.ValueInt64() == 0) {
toDelete = append(toDelete, "mtu")
body.MTU = nil
}
if len(toDelete) > 0 {
body.Delete = &toDelete
}
err := r.client.Node(plan.NodeName.ValueString()).UpdateNetworkInterface(ctx, plan.Name.ValueString(), body)
if err != nil {
resp.Diagnostics.AddError(
"Error updating Linux VLAN interface",
"Could not update Linux VLAN, unexpected error: "+err.Error(),
)
return
}
r.read(ctx, &plan, &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}
resp.Diagnostics.Append(resp.State.Set(ctx, plan)...)
err = r.client.Node(state.NodeName.ValueString()).ReloadNetworkConfiguration(ctx)
if err != nil {
resp.Diagnostics.AddError(
"Error reloading network configuration",
fmt.Sprintf("Could not reload network configuration on node '%s', unexpected error: %s",
state.NodeName.ValueString(), err.Error()),
)
}
}
// Delete deletes a Linux VLAN interface.
//
//nolint:dupl
func (r *linuxVLANResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var state linuxVLANResourceModel
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
err := r.client.Node(state.NodeName.ValueString()).DeleteNetworkInterface(ctx, state.Name.ValueString())
if err != nil {
if strings.Contains(err.Error(), "interface does not exist") {
resp.Diagnostics.AddWarning(
"Linux VLAN interface does not exist",
fmt.Sprintf("Could not delete Linux VLAN '%s', interface does not exist, "+
"or has already been deleted outside of Terraform.", state.Name.ValueString()),
)
} else {
resp.Diagnostics.AddError(
"Error deleting Linux VLAN interface",
fmt.Sprintf("Could not delete Linux VLAN '%s', unexpected error: %s",
state.Name.ValueString(), err.Error()),
)
}
return
}
err = r.client.Node(state.NodeName.ValueString()).ReloadNetworkConfiguration(ctx)
if err != nil {
resp.Diagnostics.AddError(
"Error reloading network configuration",
fmt.Sprintf("Could not reload network configuration on node '%s', unexpected error: %s",
state.NodeName.ValueString(), err.Error()),
)
}
}
func (r *linuxVLANResource) ImportState(
ctx context.Context,
req resource.ImportStateRequest,
resp *resource.ImportStateResponse,
) {
idParts := strings.Split(req.ID, ":")
if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" {
resp.Diagnostics.AddError(
"Unexpected Import Identifier",
fmt.Sprintf("Expected import identifier with format: node_name:iface. Got: %q", req.ID),
)
return
}
nodeName := idParts[0]
iface := idParts[1]
state := linuxVLANResourceModel{
ID: types.StringValue(req.ID),
NodeName: types.StringValue(nodeName),
Name: types.StringValue(iface),
}
r.read(ctx, &state, &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}
diags := resp.State.Set(ctx, state)
resp.Diagnostics.Append(diags...)
}

View File

@ -0,0 +1,401 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package provider
import (
"context"
"fmt"
"regexp"
"strings"
"github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/provider"
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/bpg/terraform-provider-proxmox/internal/network"
"github.com/bpg/terraform-provider-proxmox/proxmox"
"github.com/bpg/terraform-provider-proxmox/proxmox/api"
"github.com/bpg/terraform-provider-proxmox/proxmox/nodes"
"github.com/bpg/terraform-provider-proxmox/proxmox/ssh"
"github.com/bpg/terraform-provider-proxmox/utils"
)
// Ensure the implementation satisfies the expected interfaces.
var _ provider.Provider = &proxmoxProvider{}
// New is a helper function to simplify provider server and testing implementation.
func New(version string) func() provider.Provider {
return func() provider.Provider {
return &proxmoxProvider{
version: version,
}
}
}
type proxmoxProvider struct {
// version is set to the provider version on release, "dev" when the
// provider is built and ran locally, and "test" when running acceptance
// testing.
version string
}
// proxmoxProviderModel maps provider schema data.
type proxmoxProviderModel struct {
APIToken types.String `tfsdk:"api_token"`
Endpoint types.String `tfsdk:"endpoint"`
Insecure types.Bool `tfsdk:"insecure"`
OTP types.String `tfsdk:"otp"`
Username types.String `tfsdk:"username"`
Password types.String `tfsdk:"password"`
SSH []struct {
Agent types.Bool `tfsdk:"agent"`
AgentSocket types.String `tfsdk:"agent_socket"`
Password types.String `tfsdk:"password"`
Username types.String `tfsdk:"username"`
Nodes []struct {
Name types.String `tfsdk:"name"`
Address types.String `tfsdk:"address"`
} `tfsdk:"node"`
} `tfsdk:"ssh"`
}
func (p *proxmoxProvider) Metadata(_ context.Context, _ provider.MetadataRequest, resp *provider.MetadataResponse) {
// resp.TypeName = "proxmox"
resp.TypeName = "proxmox_virtual_environment"
resp.Version = p.version
}
func (p *proxmoxProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp *provider.SchemaResponse) {
resp.Schema = schema.Schema{
// Attributes specified in alphabetical order.
Attributes: map[string]schema.Attribute{
"api_token": schema.StringAttribute{
Description: "The API token for the Proxmox VE API.",
Optional: true,
Sensitive: true,
Validators: []validator.String{
stringvalidator.RegexMatches(
regexp.MustCompile(`^\S+@\w+!\S+=([a-zA-Z0-9-]+)$`),
`must be a valid API token, e.g. 'USER@REALM!TOKENID=UUID'`,
),
},
},
"endpoint": schema.StringAttribute{
Description: "The endpoint for the Proxmox VE API.",
Optional: true,
Validators: []validator.String{
stringvalidator.LengthAtLeast(1),
},
},
"insecure": schema.BoolAttribute{
Description: "Whether to skip the TLS verification step.",
Optional: true,
},
"otp": schema.StringAttribute{
Description: "The one-time password for the Proxmox VE API.",
Optional: true,
DeprecationMessage: "The `otp` attribute is deprecated and will be removed in a future release. " +
"Please use the `api_token` attribute instead.",
},
"password": schema.StringAttribute{
Description: "The password for the Proxmox VE API.",
Optional: true,
Sensitive: true,
},
"username": schema.StringAttribute{
Description: "The username for the Proxmox VE API.",
Optional: true,
},
},
Blocks: map[string]schema.Block{
// have to define it as a list due to backwards compatibility
"ssh": schema.ListNestedBlock{
Description: "The SSH configuration for the Proxmox nodes.",
Validators: []validator.List{
listvalidator.SizeAtMost(1),
},
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
"agent": schema.BoolAttribute{
Description: "Whether to use the SSH agent for authentication. " +
"Defaults to `false`.",
Optional: true,
},
"agent_socket": schema.StringAttribute{
Description: "The path to the SSH agent socket. " +
"Defaults to the value of the `SSH_AUTH_SOCK` " +
"environment variable.",
Optional: true,
},
"password": schema.StringAttribute{
Description: "The password used for the SSH connection. " +
"Defaults to the value of the `password` field of the " +
"`provider` block.",
Optional: true,
Sensitive: true,
},
"username": schema.StringAttribute{
Description: "The username used for the SSH connection. " +
"Defaults to the value of the `username` field of the " +
"`provider` block.",
Optional: true,
},
},
Blocks: map[string]schema.Block{
"node": schema.ListNestedBlock{
Description: "Overrides for SSH connection configuration for a Proxmox VE node.",
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
"name": schema.StringAttribute{
Description: "The name of the Proxmox VE node.",
Required: true,
},
"address": schema.StringAttribute{
Description: "The address of the Proxmox VE node.",
Required: true,
},
},
},
},
},
},
},
},
}
}
func (p *proxmoxProvider) Configure(
ctx context.Context,
req provider.ConfigureRequest,
resp *provider.ConfigureResponse,
) {
tflog.Info(ctx, "Configuring the Proxmox provider...")
// Retrieve provider data from configuration
var config proxmoxProviderModel
diags := req.Config.Get(ctx, &config)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
// If practitioner provided a configuration value for any of the
// attributes, it must be a known value.
if config.Endpoint.IsUnknown() {
resp.Diagnostics.AddAttributeError(
path.Root("endpoint"),
"Unknown Proxmox VE API Endpoint",
"The provider cannot create the Proxmox VE API client as there is an unknown configuration value "+
"for the API endpoint. Either target apply the source of the value first, set the value statically in "+
"the configuration, or use the PROXMOX_VE_ENDPOINT environment variable.",
)
}
if resp.Diagnostics.HasError() {
return
}
// Default values to environment variables, but override
// with Terraform configuration value if set.
// Check environment variables
apiToken := utils.GetAnyStringEnv("PROXMOX_VE_API_TOKEN")
endpoint := utils.GetAnyStringEnv("PROXMOX_VE_ENDPOINT")
insecure := utils.GetAnyBoolEnv("PROXMOX_VE_INSECURE")
username := utils.GetAnyStringEnv("PROXMOX_VE_USERNAME")
password := utils.GetAnyStringEnv("PROXMOX_VE_PASSWORD")
if !config.APIToken.IsNull() {
apiToken = config.APIToken.ValueString()
}
if !config.Endpoint.IsNull() {
endpoint = config.Endpoint.ValueString()
}
if !config.Insecure.IsNull() {
insecure = config.Insecure.ValueBool()
}
if !config.Username.IsNull() {
username = config.Username.ValueString()
}
if !config.Password.IsNull() {
password = config.Password.ValueString()
}
if endpoint == "" {
resp.Diagnostics.AddAttributeError(
path.Root("endpoint"),
"Missing Proxmox VE API Endpoint",
"The provider cannot create the Proxmox VE API client as there is a missing or empty value for the API endpoint. "+
"Set the host value in the configuration or use the PROXMOX_VE_ENDPOINT environment variable. "+
"If either is already set, ensure the value is not empty.",
)
}
if resp.Diagnostics.HasError() {
return
}
// Create the Proxmox VE API client
creds, err := api.NewCredentials(username, password, "", apiToken)
if err != nil {
resp.Diagnostics.AddError(
"Unable to create Proxmox VE API credentials",
err.Error(),
)
}
conn, err := api.NewConnection(
endpoint,
insecure,
)
if err != nil {
resp.Diagnostics.AddError(
"Unable to create Proxmox VE API connection",
err.Error(),
)
}
if resp.Diagnostics.HasError() {
return
}
apiClient, err := api.NewClient(creds, conn)
if err != nil {
resp.Diagnostics.AddError(
"Unable to create Proxmox VE API client",
err.Error(),
)
}
sshUsername := utils.GetAnyStringEnv("PROXMOX_VE_SSH_USERNAME")
sshPassword := utils.GetAnyStringEnv("PROXMOX_VE_SSH_PASSWORD")
sshAgent := utils.GetAnyBoolEnv("PROXMOX_VE_SSH_AGENT")
sshAgentSocket := utils.GetAnyStringEnv("SSH_AUTH_SOCK", "PROXMOX_VE_SSH_AUTH_SOCK")
nodeOverrides := map[string]string{}
if len(config.SSH) > 0 {
if !config.SSH[0].Username.IsNull() {
sshUsername = config.SSH[0].Username.ValueString()
}
if !config.SSH[0].Password.IsNull() {
sshPassword = config.SSH[0].Password.ValueString()
}
if !config.SSH[0].Agent.IsNull() {
sshAgent = config.SSH[0].Agent.ValueBool()
}
if !config.SSH[0].AgentSocket.IsNull() {
sshAgentSocket = config.SSH[0].AgentSocket.ValueString()
}
for _, n := range config.SSH[0].Nodes {
nodeOverrides[n.Name.ValueString()] = n.Address.ValueString()
}
}
if sshUsername == "" {
sshUsername = strings.Split(creds.Username, "@")[0]
}
if sshPassword == "" {
sshPassword = creds.Password
}
sshClient, err := ssh.NewClient(
sshUsername, sshPassword, sshAgent, sshAgentSocket,
&apiResolverWithOverrides{
ar: apiResolver{c: apiClient},
overrides: nodeOverrides,
},
)
if err != nil {
resp.Diagnostics.AddError(
"Unable to create Proxmox VE SSH client",
err.Error(),
)
}
if resp.Diagnostics.HasError() {
return
}
client := proxmox.NewClient(apiClient, sshClient)
resp.ResourceData = client
resp.DataSourceData = client
}
func (p *proxmoxProvider) Resources(_ context.Context) []func() resource.Resource {
return []func() resource.Resource{
network.NewLinuxBridgeResource,
network.NewLinuxVLANResource,
}
}
func (p *proxmoxProvider) DataSources(_ context.Context) []func() datasource.DataSource {
return []func() datasource.DataSource{}
}
type apiResolver struct {
c api.Client
}
func (r *apiResolver) Resolve(ctx context.Context, nodeName string) (string, error) {
nc := &nodes.Client{Client: r.c, NodeName: nodeName}
networkDevices, err := nc.ListNetworkInterfaces(ctx)
if err != nil {
return "", fmt.Errorf("failed to list network devices of node \"%s\": %w", nc.NodeName, err)
}
nodeAddress := ""
for _, d := range networkDevices {
if d.Address != nil {
nodeAddress = *d.Address
break
}
}
if nodeAddress == "" {
return "", fmt.Errorf("failed to determine the IP address of node \"%s\"", nc.NodeName)
}
nodeAddressParts := strings.Split(nodeAddress, "/")
return nodeAddressParts[0], nil
}
type apiResolverWithOverrides struct {
ar apiResolver
overrides map[string]string
}
func (r *apiResolverWithOverrides) Resolve(ctx context.Context, nodeName string) (string, error) {
if ip, ok := r.overrides[nodeName]; ok {
return ip, nil
}
return r.ar.Resolve(ctx, nodeName)
}

View File

@ -0,0 +1,41 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package test
import (
"github.com/hashicorp/terraform-plugin-framework/providerserver"
"github.com/hashicorp/terraform-plugin-go/tfprotov6"
"github.com/bpg/terraform-provider-proxmox/internal/provider"
)
const (
// ProviderConfig is a shared configuration to combine with the actual
// test configuration so the Proxmox VE client is properly configured.
// It is also possible to use the PROXMOX_VE_ environment variables instead,.
ProviderConfig = `
provider "proxmox" {
username = "root@pam"
password = "password"
insecure = true
ssh {
agent = true
}
}
`
// such as updating the Makefile and running the testing through that tool.
)
// AccTestProtoV6ProviderFactories are used to instantiate a provider during
// acceptance testing. The factory function will be invoked for every Terraform
// CLI command executed to create a provider server to which the CLI can
// reattach.
//
//nolint:gochecknoglobals
var AccTestProtoV6ProviderFactories = map[string]func() (tfprotov6.ProviderServer, error){
"proxmox": providerserver.NewProtocol6WithError(provider.New("test")()),
}

View File

@ -0,0 +1,74 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package test
import (
"testing"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)
func Test_LinuxBridgeResource(t *testing.T) {
t.Parallel()
resourceName := "proxmox_virtual_environment_network_linux_bridge.test"
resource.Test(t, resource.TestCase{
ProtoV6ProviderFactories: AccTestProtoV6ProviderFactories,
Steps: []resource.TestStep{
// Create and Read testing
{
Config: ProviderConfig + `
resource "proxmox_virtual_environment_network_linux_bridge" "test" {
node_name = "pve"
name = "vmbr99"
address = "3.3.3.3/24"
comment = "created by terraform"
mtu = 1499
}
`,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, "name", "vmbr99"),
resource.TestCheckResourceAttr(resourceName, "address", "3.3.3.3/24"),
resource.TestCheckResourceAttr(resourceName, "comment", "created by terraform"),
resource.TestCheckResourceAttr(resourceName, "vlan_aware", "true"),
resource.TestCheckResourceAttr(resourceName, "mtu", "1499"),
resource.TestCheckResourceAttrSet(resourceName, "id"),
),
},
// ImportState testing
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
// Update testing
{
Config: ProviderConfig + `
resource "proxmox_virtual_environment_network_linux_bridge" "test" {
node_name = "pve"
name = "vmbr99"
address = "1.1.1.1/24"
address6 = "FE80:0000:0000:0000:0202:B3FF:FE1E:8329/64"
comment = "updated by terraform"
vlan_aware = false
mtu = null
}
`,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, "name", "vmbr99"),
resource.TestCheckResourceAttr(resourceName, "address", "1.1.1.1/24"),
resource.TestCheckResourceAttr(resourceName, "address6", "FE80:0000:0000:0000:0202:B3FF:FE1E:8329/64"),
resource.TestCheckResourceAttr(resourceName, "comment", "updated by terraform"),
resource.TestCheckResourceAttr(resourceName, "vlan_aware", "false"),
resource.TestCheckNoResourceAttr(resourceName, "mtu"),
resource.TestCheckResourceAttrSet(resourceName, "id"),
),
},
},
})
}

View File

@ -0,0 +1,72 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package test
import (
"testing"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)
func Test_LinuxVLANResource(t *testing.T) {
t.Parallel()
resourceName := "proxmox_virtual_environment_network_linux_vlan.test"
resource.Test(t, resource.TestCase{
ProtoV6ProviderFactories: AccTestProtoV6ProviderFactories,
Steps: []resource.TestStep{
// Create and Read testing
{
Config: ProviderConfig + `
resource "proxmox_virtual_environment_network_linux_vlan" "test" {
node_name = "pve"
name = "ens18.33"
comment = "created by terraform"
mtu = 1499
}
`,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, "name", "ens18.33"),
resource.TestCheckResourceAttr(resourceName, "comment", "created by terraform"),
resource.TestCheckResourceAttr(resourceName, "vlan", "33"),
resource.TestCheckResourceAttr(resourceName, "interface", "ens18"),
resource.TestCheckResourceAttrSet(resourceName, "id"),
),
},
// ImportState testing
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
// Update testing
{
Config: ProviderConfig + `
resource "proxmox_virtual_environment_network_linux_vlan" "test" {
node_name = "pve"
name = "ens18.33"
address = "1.1.1.1/24"
address6 = "FE80:0000:0000:0000:0202:B3FF:FE1E:8329/64"
comment = "updated by terraform"
mtu = null
}
`,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, "name", "ens18.33"),
resource.TestCheckResourceAttr(resourceName, "address", "1.1.1.1/24"),
resource.TestCheckResourceAttr(resourceName, "address6", "FE80:0000:0000:0000:0202:B3FF:FE1E:8329/64"),
resource.TestCheckResourceAttr(resourceName, "comment", "updated by terraform"),
resource.TestCheckResourceAttr(resourceName, "vlan", "33"),
resource.TestCheckResourceAttr(resourceName, "interface", "ens18"),
resource.TestCheckNoResourceAttr(resourceName, "mtu"),
resource.TestCheckResourceAttrSet(resourceName, "id"),
),
},
},
})
}

View File

@ -53,6 +53,16 @@ func (r *CustomBool) UnmarshalJSON(b []byte) error {
return nil
}
// Pointer returns a pointers.
func (r CustomBool) Pointer() *CustomBool {
return &r
}
// PointerBool returns a pointer to a boolean.
func (r *CustomBool) PointerBool() *bool {
return (*bool)(r)
}
// MarshalJSON converts a boolean to a JSON value.
func (r *CustomCommaSeparatedList) MarshalJSON() ([]byte, error) {
s := strings.Join(*r, ",")

118
internal/types/ip_addr.go Normal file
View File

@ -0,0 +1,118 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package types
import (
"context"
"fmt"
"net"
"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/types/basetypes"
"github.com/hashicorp/terraform-plugin-go/tftypes"
)
// Ensure the implementation satisfies the expected interfaces.
var _ basetypes.StringTypable = IPAddrType{}
// IPAddrType is a type that represents an IP address.
type IPAddrType struct {
basetypes.StringType
}
// Equal returns true if the two types are equal.
func (t IPAddrType) Equal(o attr.Type) bool {
other, ok := o.(IPAddrType)
if !ok {
return false
}
return t.StringType.Equal(other.StringType)
}
// String returns a string representation of the type.
func (t IPAddrType) String() string {
return "IPAddrType"
}
// ValueFromString converts a string value to a StringValuable.
func (t IPAddrType) ValueFromString(
_ context.Context, in basetypes.StringValue,
) (basetypes.StringValuable, diag.Diagnostics) {
value := IPAddrValue{
StringValue: in,
}
return value, nil
}
// ValueFromTerraform converts a Terraform value to a StringValuable.
func (t IPAddrType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) {
attrValue, err := t.StringType.ValueFromTerraform(ctx, in)
if err != nil {
return nil, fmt.Errorf("unexpected error converting Terraform value to StringValue: %w", 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
}
// ValueType returns the underlying value type.
func (t IPAddrType) ValueType(_ context.Context) attr.Value {
return IPAddrValue{}
}
// Validate ensures the value is valid IP address.
func (t IPAddrType) Validate(_ context.Context, value tftypes.Value, valuePath path.Path) diag.Diagnostics {
if value.IsNull() || !value.IsKnown() {
return nil
}
var diags diag.Diagnostics
var valueString string
if err := value.As(&valueString); err != nil {
diags.AddAttributeError(
valuePath,
"Invalid Terraform Value",
"An unexpected error occurred while attempting to convert a Terraform value to a string. "+
"This generally is an issue with the provider schema implementation. "+
"Please contact the provider developers.\n\n"+
"Path: "+valuePath.String()+"\n"+
"Error: "+err.Error(),
)
return diags
}
if ip := net.ParseIP(valueString); ip == nil {
diags.AddAttributeError(
valuePath,
"Invalid IP String Value",
"An unexpected error occurred while converting a string value that was expected to be IPv4/IPv6.\n\n"+
"Path: "+valuePath.String()+"\n"+
"Given Value: "+valueString,
)
return diags
}
return diags
}

View File

@ -0,0 +1,122 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package types
import (
"context"
"testing"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-go/tftypes"
)
func Test_IPAddrTypeValueFromTerraform(t *testing.T) {
t.Parallel()
tests := map[string]struct {
val tftypes.Value
expected func(val IPAddrValue) bool
expectError bool
}{
"null value": {
val: tftypes.NewValue(tftypes.String, nil),
expected: func(val IPAddrValue) bool {
return val.IsNull()
},
},
"unknown value": {
val: tftypes.NewValue(tftypes.String, tftypes.UnknownValue),
expected: func(val IPAddrValue) bool {
return val.IsUnknown()
},
},
"valid IPv4": {
val: tftypes.NewValue(tftypes.String, "1.2.3.4"),
expected: func(val IPAddrValue) bool {
return val.ValueString() == "1.2.3.4"
},
},
"valid IPv6": {
val: tftypes.NewValue(tftypes.String, "2001:0db8:85a3:0000:0000:8a2e:0370:7334"),
expected: func(val IPAddrValue) bool {
return val.ValueString() == "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
},
},
}
for name, test := range tests {
name, test := name, test
t.Run(name, func(t *testing.T) {
t.Parallel()
ctx := context.TODO()
val, err := IPAddrType{}.ValueFromTerraform(ctx, test.val)
if err == nil && test.expectError {
t.Fatal("expected error, got no error")
}
if err != nil && !test.expectError {
t.Fatalf("got unexpected error: %s", err)
}
if !test.expected(val.(IPAddrValue)) {
t.Errorf("unexpected result")
}
})
}
}
func Test_IPAddrTypeValidate(t *testing.T) {
t.Parallel()
type testCase struct {
val tftypes.Value
expectError bool
}
tests := map[string]testCase{
"not a string": {
val: tftypes.NewValue(tftypes.Bool, true),
expectError: true,
},
"unknown string": {
val: tftypes.NewValue(tftypes.String, tftypes.UnknownValue),
},
"null string": {
val: tftypes.NewValue(tftypes.String, nil),
},
"valid IPv4 string": {
val: tftypes.NewValue(tftypes.String, "1.2.3.4"),
},
"valid IPv6 string": {
val: tftypes.NewValue(tftypes.String, "2001:0db8:85a3:0000:0000:8a2e:0370:7334"),
},
"invalid string": {
val: tftypes.NewValue(tftypes.String, "not ok"),
expectError: true,
},
}
for name, test := range tests {
name, test := name, test
t.Run(name, func(t *testing.T) {
t.Parallel()
ctx := context.TODO()
diags := IPAddrType{}.Validate(ctx, test.val, path.Root("test"))
if !diags.HasError() && test.expectError {
t.Fatal("expected error, got no error")
}
if diags.HasError() && !test.expectError {
t.Fatalf("got unexpected error: %s", diags)
}
})
}
}

View File

@ -0,0 +1,46 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package types
import (
"context"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
)
// Ensure the implementation satisfies the expected interfaces.
var _ basetypes.StringValuable = IPAddrValue{}
// IPAddrValue is a type that represents an IP address value.
type IPAddrValue struct {
basetypes.StringValue
}
// Equal returns true if the two values are equal.
func (v IPAddrValue) Equal(o attr.Value) bool {
other, ok := o.(IPAddrValue)
if !ok {
return false
}
return v.StringValue.Equal(other.StringValue)
}
// Type returns the type of the value.
func (v IPAddrValue) Type(_ context.Context) attr.Type {
return IPAddrType{}
}
// NewIPAddrPointerValue returns a new IPAddrValue from a string pointer.
func NewIPAddrPointerValue(value *string) IPAddrValue {
return IPAddrValue{
StringValue: types.StringPointerValue(value),
}
}

119
internal/types/ip_cidr.go Normal file
View File

@ -0,0 +1,119 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package types
import (
"context"
"fmt"
"net"
"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/types/basetypes"
"github.com/hashicorp/terraform-plugin-go/tftypes"
)
// Ensure the implementation satisfies the expected interfaces.
var _ basetypes.StringTypable = IPCIDRType{}
// IPCIDRType is a type that represents an IP address in CIDR notation.
type IPCIDRType struct {
basetypes.StringType
}
// Equal returns true if the two types are equal.
func (t IPCIDRType) Equal(o attr.Type) bool {
other, ok := o.(IPCIDRType)
if !ok {
return false
}
return t.StringType.Equal(other.StringType)
}
// String returns a string representation of the type.
func (t IPCIDRType) String() string {
return "IPCIDRType"
}
// ValueFromString converts a string value to a StringValuable.
func (t IPCIDRType) ValueFromString(
_ context.Context, in basetypes.StringValue,
) (basetypes.StringValuable, diag.Diagnostics) {
value := IPCIDRValue{
StringValue: in,
}
return value, nil
}
// ValueFromTerraform converts a Terraform value to a StringValuable.
func (t IPCIDRType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) {
attrValue, err := t.StringType.ValueFromTerraform(ctx, in)
if err != nil {
return nil, fmt.Errorf("unexpected error converting Terraform value to StringValue: %w", 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
}
// ValueType returns the underlying value type.
func (t IPCIDRType) ValueType(_ context.Context) attr.Value {
return IPCIDRValue{}
}
// Validate ensures the value is valid IP address in CIDR notation.
func (t IPCIDRType) Validate(_ context.Context, value tftypes.Value, valuePath path.Path) diag.Diagnostics {
if value.IsNull() || !value.IsKnown() {
return nil
}
var diags diag.Diagnostics
var valueString string
if err := value.As(&valueString); err != nil {
diags.AddAttributeError(
valuePath,
"Invalid Terraform Value",
"An unexpected error occurred while attempting to convert a Terraform value to a string. "+
"This generally is an issue with the provider schema implementation. "+
"Please contact the provider developers.\n\n"+
"Path: "+valuePath.String()+"\n"+
"Error: "+err.Error(),
)
return diags
}
if _, _, err := net.ParseCIDR(valueString); err != nil {
diags.AddAttributeError(
valuePath,
"Invalid IP/CIDR String Value",
"An unexpected error occurred while converting a string value that was expected to be IP/CIDR.\n\n"+
"Path: "+valuePath.String()+"\n"+
"Given Value: "+valueString+"\n"+
"Error: "+err.Error(),
)
return diags
}
return diags
}

View File

@ -0,0 +1,130 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package types
import (
"context"
"testing"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-go/tftypes"
)
func Test_IPCIDRTypeValueFromTerraform(t *testing.T) {
t.Parallel()
tests := map[string]struct {
val tftypes.Value
expected func(val IPCIDRValue) bool
expectError bool
}{
"null value": {
val: tftypes.NewValue(tftypes.String, nil),
expected: func(val IPCIDRValue) bool {
return val.IsNull()
},
},
"unknown value": {
val: tftypes.NewValue(tftypes.String, tftypes.UnknownValue),
expected: func(val IPCIDRValue) bool {
return val.IsUnknown()
},
},
"valid IPv4/CIDR": {
val: tftypes.NewValue(tftypes.String, "1.2.3.4/32"),
expected: func(val IPCIDRValue) bool {
return val.ValueString() == "1.2.3.4/32"
},
},
"valid IPv6/CIDR": {
val: tftypes.NewValue(tftypes.String, "2001:db8::/32"),
expected: func(val IPCIDRValue) bool {
return val.ValueString() == "2001:db8::/32"
},
},
}
for name, test := range tests {
name, test := name, test
t.Run(name, func(t *testing.T) {
t.Parallel()
ctx := context.TODO()
val, err := IPCIDRType{}.ValueFromTerraform(ctx, test.val)
if err == nil && test.expectError {
t.Fatal("expected error, got no error")
}
if err != nil && !test.expectError {
t.Fatalf("got unexpected error: %s", err)
}
if !test.expected(val.(IPCIDRValue)) {
t.Errorf("unexpected result")
}
})
}
}
func Test_IPCIDRTypeValidate(t *testing.T) {
t.Parallel()
type testCase struct {
val tftypes.Value
expectError bool
}
tests := map[string]testCase{
"not a string": {
val: tftypes.NewValue(tftypes.Bool, true),
expectError: true,
},
"unknown string": {
val: tftypes.NewValue(tftypes.String, tftypes.UnknownValue),
},
"null string": {
val: tftypes.NewValue(tftypes.String, nil),
},
"valid IPv4 string": {
val: tftypes.NewValue(tftypes.String, "1.2.3.4/32"),
},
"valid IPv6 string": {
val: tftypes.NewValue(tftypes.String, "2001:db8::/32"),
},
"invalid string": {
val: tftypes.NewValue(tftypes.String, "not ok"),
expectError: true,
},
"invalid IPv4 string no CIDR": {
val: tftypes.NewValue(tftypes.String, "1.2.3.4"),
expectError: true,
},
"invalid IPv6 string no CIDR": {
val: tftypes.NewValue(tftypes.String, "2001:db8::"),
expectError: true,
},
}
for name, test := range tests {
name, test := name, test
t.Run(name, func(t *testing.T) {
t.Parallel()
ctx := context.TODO()
diags := IPCIDRType{}.Validate(ctx, test.val, path.Root("test"))
if !diags.HasError() && test.expectError {
t.Fatal("expected error, got no error")
}
if diags.HasError() && !test.expectError {
t.Fatalf("got unexpected error: %s", diags)
}
})
}
}

View File

@ -0,0 +1,46 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package types
import (
"context"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
)
// Ensure the implementation satisfies the expected interfaces.
var _ basetypes.StringValuable = IPCIDRValue{}
// IPCIDRValue is a type that represents an IP address in CIDR notation.
type IPCIDRValue struct {
basetypes.StringValue
}
// Equal returns true if the two values are equal.
func (v IPCIDRValue) Equal(o attr.Value) bool {
other, ok := o.(IPCIDRValue)
if !ok {
return false
}
return v.StringValue.Equal(other.StringValue)
}
// Type returns the type of the value.
func (v IPCIDRValue) Type(_ context.Context) attr.Type {
return IPCIDRType{}
}
// NewIPCIDRPointerValue returns a new IPCIDRValue from a string pointer.
func NewIPCIDRPointerValue(value *string) IPCIDRValue {
return IPCIDRValue{
StringValue: types.StringPointerValue(value),
}
}

67
main.go
View File

@ -1,31 +1,80 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package main
import (
"context"
"flag"
"log"
"github.com/hashicorp/terraform-plugin-framework/providerserver"
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
"github.com/hashicorp/terraform-plugin-go/tfprotov6"
"github.com/hashicorp/terraform-plugin-go/tfprotov6/tf6server"
"github.com/hashicorp/terraform-plugin-mux/tf5to6server"
"github.com/hashicorp/terraform-plugin-mux/tf6muxserver"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/plugin"
newProvider "github.com/bpg/terraform-provider-proxmox/internal/provider"
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/provider"
)
// If you do not have terraform installed, you can remove the formatting command, but it's suggested to
// ensure the documentation is formatted properly.
//go:generate terraform fmt -recursive ./example/
// Run the docs generation tool, check its repository for more information on how it works and how docs
// can be customized.
//go:generate go run -modfile=tools/go.mod github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs
func main() {
ctx := context.Background()
var debug bool
flag.BoolVar(&debug, "debug", false, "set to true to run the provider with support for debuggers like delve")
flag.Parse()
opts := &plugin.ServeOpts{
Debug: debug,
ProviderAddr: "registry.terraform.io/bpg/proxmox",
ProviderFunc: func() *schema.Provider {
return provider.ProxmoxVirtualEnvironment()
upgradedSdkServer, err := tf5to6server.UpgradeServer(
ctx,
func() tfprotov5.ProviderServer {
return schema.NewGRPCProviderServer(
provider.ProxmoxVirtualEnvironment(),
)
},
)
if err != nil {
log.Fatal(err)
}
providers := []func() tfprotov6.ProviderServer{
providerserver.NewProtocol6(newProvider.New("dev")()),
func() tfprotov6.ProviderServer {
return upgradedSdkServer
},
}
plugin.Serve(opts)
muxServer, err := tf6muxserver.NewMuxServer(ctx, providers...)
if err != nil {
log.Fatal(err)
}
var serveOpts []tf6server.ServeOpt
if debug {
serveOpts = append(serveOpts, tf6server.WithManagedDebug())
}
err = tf6server.Serve(
"registry.terraform.io/bpg/proxmox",
muxServer.ProviderServer,
serveOpts...,
)
if err != nil {
log.Fatal(err)
}
}

View File

@ -6,7 +6,9 @@
package access
import "github.com/bpg/terraform-provider-proxmox/proxmox/types"
import (
"github.com/bpg/terraform-provider-proxmox/internal/types"
)
// ACLGetResponseBody contains the body from an access control list response.
type ACLGetResponseBody struct {

View File

@ -13,8 +13,8 @@ import (
"net/url"
"sort"
"github.com/bpg/terraform-provider-proxmox/internal/types"
"github.com/bpg/terraform-provider-proxmox/proxmox/api"
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
)
func (c *Client) rolesPath() string {

View File

@ -6,7 +6,9 @@
package access
import "github.com/bpg/terraform-provider-proxmox/proxmox/types"
import (
"github.com/bpg/terraform-provider-proxmox/internal/types"
)
// RoleCreateRequestBody contains the data for an access group create request.
type RoleCreateRequestBody struct {

View File

@ -14,8 +14,8 @@ import (
"sort"
"time"
"github.com/bpg/terraform-provider-proxmox/internal/types"
"github.com/bpg/terraform-provider-proxmox/proxmox/api"
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
)
func (c *Client) usersPath() string {

View File

@ -6,7 +6,9 @@
package access
import "github.com/bpg/terraform-provider-proxmox/proxmox/types"
import (
"github.com/bpg/terraform-provider-proxmox/internal/types"
)
// UserChangePasswordRequestBody contains the data for a user password change request.
type UserChangePasswordRequestBody struct {

View File

@ -7,6 +7,7 @@
package api
import (
"context"
"net/http"
)
@ -18,5 +19,5 @@ type Authenticator interface {
IsRoot() bool
// AuthenticateRequest adds authentication data to a new request.
AuthenticateRequest(req *http.Request) error
AuthenticateRequest(ctx context.Context, req *http.Request) error
}

View File

@ -17,6 +17,7 @@ import (
"net/http"
"net/url"
"strings"
"time"
"github.com/google/go-querystring/query"
"github.com/hashicorp/terraform-plugin-log/tflog"
@ -29,7 +30,9 @@ import (
var ErrNoDataObjectInResponse = errors.New("the server did not include a data object in the response")
const (
basePathJSONAPI = "api2/json"
// the large timeout is to allow for large file uploads.
httpClientTimeout = 5 * time.Minute
basePathJSONAPI = "api2/json"
)
// Client is an interface for performing requests against the Proxmox API.
@ -83,8 +86,11 @@ func NewConnection(endpoint string, insecure bool) (*Connection, error) {
}
return &Connection{
endpoint: strings.TrimRight(u.String(), "/"),
httpClient: &http.Client{Transport: transport},
endpoint: strings.TrimRight(u.String(), "/"),
httpClient: &http.Client{
Transport: transport,
Timeout: httpClientTimeout,
},
}, nil
}
@ -95,7 +101,7 @@ type client struct {
}
// NewClient creates and initializes a VirtualEnvironmentClient instance.
func NewClient(ctx context.Context, creds *Credentials, conn *Connection) (Client, error) {
func NewClient(creds *Credentials, conn *Connection) (Client, error) {
if creds == nil {
return nil, errors.New("credentials must not be nil")
}
@ -111,7 +117,7 @@ func NewClient(ctx context.Context, creds *Credentials, conn *Connection) (Clien
if creds.APIToken != nil {
auth, err = NewTokenAuthenticator(*creds.APIToken)
} else {
auth, err = NewTicketAuthenticator(ctx, conn, creds)
auth, err = NewTicketAuthenticator(conn, creds)
}
if err != nil {
@ -202,7 +208,7 @@ func (c *client) DoRequest(
req.Header.Add("Content-Type", reqBodyType)
}
err = c.auth.AuthenticateRequest(req)
err = c.auth.AuthenticateRequest(ctx, req)
if err != nil {
return fmt.Errorf("failed to authenticate HTTP %s request (path: %s) - Reason: %w",
method,
@ -228,6 +234,7 @@ func (c *client) DoRequest(
return err
}
//nolint:nestif
if responseBody != nil {
err = json.NewDecoder(res.Body).Decode(responseBody)
if err != nil {
@ -248,14 +255,27 @@ func (c *client) DoRequest(
err,
)
}
tflog.Warn(ctx, "unhandled HTTP response body", map[string]interface{}{
"data": string(data),
})
if len(data) > 0 {
dr := dataResponse{}
if err2 := json.NewDecoder(bytes.NewReader(data)).Decode(&dr); err2 == nil {
if dr.Data == nil {
return nil
}
}
tflog.Warn(ctx, "unhandled HTTP response body", map[string]interface{}{
"data": dr.Data,
})
}
}
return nil
}
type dataResponse struct {
Data interface{} `json:"data"`
}
// ExpandPath expands the given path to an absolute path.
func (c *client) ExpandPath(path string) string {
return path

View File

@ -21,12 +21,14 @@ import (
)
type ticketAuthenticator struct {
authenticationData *AuthenticationResponseData
conn *Connection
authRequest string
authData *AuthenticationResponseData
}
// NewTicketAuthenticator returns a new ticket authenticator.
func NewTicketAuthenticator(ctx context.Context, conn *Connection, creds *Credentials) (Authenticator, error) {
reqStr := fmt.Sprintf(
func NewTicketAuthenticator(conn *Connection, creds *Credentials) (Authenticator, error) {
authRequest := fmt.Sprintf(
"username=%s&password=%s",
url.QueryEscape(creds.Username),
url.QueryEscape(creds.Password),
@ -34,14 +36,25 @@ func NewTicketAuthenticator(ctx context.Context, conn *Connection, creds *Creden
// OTP is optional, and probably doesn't make much sense for most provider users.
if creds.OTP != nil {
reqStr = fmt.Sprintf("%s&otp=%s", reqStr, url.QueryEscape(*creds.OTP))
authRequest = fmt.Sprintf("%s&otp=%s", authRequest, url.QueryEscape(*creds.OTP))
}
return &ticketAuthenticator{
conn: conn,
authRequest: authRequest,
}, nil
}
func (t *ticketAuthenticator) authenticate(ctx context.Context) (*AuthenticationResponseData, error) {
if t.authData != nil {
return t.authData, nil
}
req, err := http.NewRequestWithContext(
ctx,
http.MethodPost,
fmt.Sprintf("%s/%s/access/ticket", conn.endpoint, basePathJSONAPI),
bytes.NewBufferString(reqStr),
fmt.Sprintf("%s/%s/access/ticket", t.conn.endpoint, basePathJSONAPI),
bytes.NewBufferString(t.authRequest),
)
if err != nil {
return nil, fmt.Errorf("failed to create authentication request: %w", err)
@ -49,12 +62,12 @@ func NewTicketAuthenticator(ctx context.Context, conn *Connection, creds *Creden
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
tflog.Debug(ctx, "sending authentication request", map[string]interface{}{
tflog.Debug(ctx, "Sending authentication request", map[string]interface{}{
"path": req.URL.Path,
})
//nolint:bodyclose
res, err := conn.httpClient.Do(req)
res, err := t.conn.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to retrieve authentication response: %w", err)
}
@ -91,28 +104,29 @@ func NewTicketAuthenticator(ctx context.Context, conn *Connection, creds *Creden
return nil, errors.New("the server did not include the username in the authentication response")
}
return &ticketAuthenticator{
authenticationData: resBody.Data,
}, nil
t.authData = resBody.Data
return resBody.Data, nil
}
func (t *ticketAuthenticator) IsRoot() bool {
return t.authenticationData.Username == rootUsername
return t.authData != nil && t.authData.Username == rootUsername
}
// AuthenticateRequest adds authentication data to a new request.
func (t *ticketAuthenticator) AuthenticateRequest(req *http.Request) error {
if t.authenticationData == nil {
return errors.New("failed to authenticate: no ticket")
func (t *ticketAuthenticator) AuthenticateRequest(ctx context.Context, req *http.Request) error {
a, err := t.authenticate(ctx)
if err != nil {
return fmt.Errorf("failed to authenticate: %w", err)
}
req.AddCookie(&http.Cookie{
Name: "PVEAuthCookie",
Value: *t.authenticationData.Ticket,
Value: *a.Ticket,
})
if req.Method != http.MethodGet {
req.Header.Add("CSRFPreventionToken", *t.authenticationData.CSRFPreventionToken)
req.Header.Add("CSRFPreventionToken", *a.CSRFPreventionToken)
}
return nil

View File

@ -6,7 +6,9 @@
package api
import "github.com/bpg/terraform-provider-proxmox/proxmox/types"
import (
"github.com/bpg/terraform-provider-proxmox/internal/types"
)
// AuthenticationResponseBody contains the body from an authentication response.
type AuthenticationResponseBody struct {

View File

@ -7,6 +7,7 @@
package api
import (
"context"
"net/http"
"strings"
)
@ -29,7 +30,7 @@ func (t *tokenAuthenticator) IsRoot() bool {
return t.username == rootUsername
}
func (t *tokenAuthenticator) AuthenticateRequest(req *http.Request) error {
func (t *tokenAuthenticator) AuthenticateRequest(_ context.Context, req *http.Request) error {
req.Header.Set("Authorization", "PVEAPIToken="+t.token)
return nil
}

View File

@ -1,10 +1,14 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package cluster
import "github.com/bpg/terraform-provider-proxmox/proxmox/types"
import (
"github.com/bpg/terraform-provider-proxmox/internal/types"
)
// NextIDRequestBody contains the data for a cluster next id request.
type NextIDRequestBody struct {

View File

@ -13,7 +13,7 @@ import (
"strconv"
"strings"
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
"github.com/bpg/terraform-provider-proxmox/internal/types"
)
// OptionsPutRequestBody is the request body for the PUT /cluster/firewall/options API call.

View File

@ -6,7 +6,9 @@
package firewall
import "github.com/bpg/terraform-provider-proxmox/proxmox/types"
import (
"github.com/bpg/terraform-provider-proxmox/internal/types"
)
// IPSetListResponseBody contains the data from an IPSet get response.
type IPSetListResponseBody struct {

View File

@ -6,7 +6,9 @@
package firewall
import "github.com/bpg/terraform-provider-proxmox/proxmox/types"
import (
"github.com/bpg/terraform-provider-proxmox/internal/types"
)
// OptionsPutRequestBody is the request body for the PUT /cluster/firewall/options API call.
type OptionsPutRequestBody struct {

View File

@ -14,8 +14,8 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/bpg/terraform-provider-proxmox/internal/types"
"github.com/bpg/terraform-provider-proxmox/proxmox/api"
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
)
// Rule is an interface for the Proxmox firewall rule API.

View File

@ -26,9 +26,9 @@ type RuleGetResponseData struct {
BaseRule
// NOTE: This is `int` in the PVE API docs, but it's actually a string in the response.
Pos string `json:"pos" url:"pos"`
Action string `json:"action" url:"action"`
Type string `json:"type" url:"type"`
Pos string `json:"pos" url:"pos"`
Action string `json:"action" url:"action"`
Type string `json:"type" url:"type"`
}
// RuleListResponseBody contains the data from a firewall rule get response.

View File

@ -6,7 +6,9 @@
package nodes
import "github.com/bpg/terraform-provider-proxmox/proxmox/types"
import (
"github.com/bpg/terraform-provider-proxmox/internal/types"
)
// CertificateDeleteRequestBody contains the data for a custom certificate delete request.
type CertificateDeleteRequestBody struct {

View File

@ -12,6 +12,7 @@ import (
"github.com/bpg/terraform-provider-proxmox/proxmox/api"
"github.com/bpg/terraform-provider-proxmox/proxmox/nodes/containers"
"github.com/bpg/terraform-provider-proxmox/proxmox/nodes/tasks"
"github.com/bpg/terraform-provider-proxmox/proxmox/nodes/vms"
)
@ -41,3 +42,10 @@ func (c *Client) VM(vmID int) *vms.Client {
VMID: vmID,
}
}
// Tasks returns a client for managing VM tasks.
func (c *Client) Tasks() *tasks.Client {
return &tasks.Client{
Client: c,
}
}

View File

@ -13,26 +13,27 @@ import (
"strconv"
"strings"
types2 "github.com/bpg/terraform-provider-proxmox/internal/types"
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
)
// CloneRequestBody contains the data for an container clone request.
type CloneRequestBody struct {
BandwidthLimit *int `json:"bwlimit,omitempty" url:"bwlimit,omitempty"`
Description *string `json:"description,omitempty" url:"description,omitempty"`
FullCopy *types.CustomBool `json:"full,omitempty" url:"full,omitempty,int"`
Hostname *string `json:"hostname,omitempty" url:"hostname,omitempty"`
PoolID *string `json:"pool,omitempty" url:"pool,omitempty"`
SnapshotName *string `json:"snapname,omitempty" url:"snapname,omitempty"`
TargetNodeName *string `json:"target,omitempty" url:"target,omitempty"`
TargetStorage *string `json:"storage,omitempty" url:"storage,omitempty"`
VMIDNew int `json:"newid" url:"newid"`
BandwidthLimit *int `json:"bwlimit,omitempty" url:"bwlimit,omitempty"`
Description *string `json:"description,omitempty" url:"description,omitempty"`
FullCopy *types2.CustomBool `json:"full,omitempty" url:"full,omitempty,int"`
Hostname *string `json:"hostname,omitempty" url:"hostname,omitempty"`
PoolID *string `json:"pool,omitempty" url:"pool,omitempty"`
SnapshotName *string `json:"snapname,omitempty" url:"snapname,omitempty"`
TargetNodeName *string `json:"target,omitempty" url:"target,omitempty"`
TargetStorage *string `json:"storage,omitempty" url:"storage,omitempty"`
VMIDNew int `json:"newid" url:"newid"`
}
// CreateRequestBody contains the data for a user create request.
type CreateRequestBody struct {
BandwidthLimit *float64 `json:"bwlimit,omitempty" url:"bwlimit,omitempty"`
ConsoleEnabled *types.CustomBool `json:"console,omitempty" url:"console,omitempty,int"`
ConsoleEnabled *types2.CustomBool `json:"console,omitempty" url:"console,omitempty,int"`
ConsoleMode *string `json:"cmode,omitempty" url:"cmode,omitempty"`
CPUArchitecture *string `json:"arch,omitempty" url:"arch,omitempty"`
CPUCores *int `json:"cores,omitempty" url:"cores,omitempty"`
@ -45,10 +46,10 @@ type CreateRequestBody struct {
DNSDomain *string `json:"searchdomain,omitempty" url:"searchdomain,omitempty"`
DNSServer *string `json:"nameserver,omitempty" url:"nameserver,omitempty"`
Features *CustomFeatures `json:"features,omitempty" url:"features,omitempty"`
Force *types.CustomBool `json:"force,omitempty" url:"force,omitempty,int"`
Force *types2.CustomBool `json:"force,omitempty" url:"force,omitempty,int"`
HookScript *string `json:"hookscript,omitempty" url:"hookscript,omitempty"`
Hostname *string `json:"hostname,omitempty" url:"hostname,omitempty"`
IgnoreUnpackErrors *types.CustomBool `json:"ignore-unpack-errors,omitempty" url:"force,omitempty,int"`
IgnoreUnpackErrors *types2.CustomBool `json:"ignore-unpack-errors,omitempty" url:"force,omitempty,int"`
Lock *string `json:"lock,omitempty" url:"lock,omitempty,int"`
MountPoints CustomMountPointArray `json:"mp,omitempty" url:"mp,omitempty,numbered"`
NetworkInterfaces CustomNetworkInterfaceArray `json:"net,omitempty" url:"net,omitempty,numbered"`
@ -56,43 +57,43 @@ type CreateRequestBody struct {
OSType *string `json:"ostype,omitempty" url:"ostype,omitempty"`
Password *string `json:"password,omitempty" url:"password,omitempty"`
PoolID *string `json:"pool,omitempty" url:"pool,omitempty"`
Protection *types.CustomBool `json:"protection,omitempty" url:"protection,omitempty,int"`
Restore *types.CustomBool `json:"restore,omitempty" url:"restore,omitempty,int"`
Protection *types2.CustomBool `json:"protection,omitempty" url:"protection,omitempty,int"`
Restore *types2.CustomBool `json:"restore,omitempty" url:"restore,omitempty,int"`
RootFS *CustomRootFS `json:"rootfs,omitempty" url:"rootfs,omitempty"`
SSHKeys *CustomSSHKeys `json:"ssh-public-keys,omitempty" url:"ssh-public-keys,omitempty"`
Start *types.CustomBool `json:"start,omitempty" url:"start,omitempty,int"`
StartOnBoot *types.CustomBool `json:"onboot,omitempty" url:"onboot,omitempty,int"`
Start *types2.CustomBool `json:"start,omitempty" url:"start,omitempty,int"`
StartOnBoot *types2.CustomBool `json:"onboot,omitempty" url:"onboot,omitempty,int"`
StartupBehavior *CustomStartupBehavior `json:"startup,omitempty" url:"startup,omitempty"`
Swap *int `json:"swap,omitempty" url:"swap,omitempty"`
Tags *string `json:"tags,omitempty" url:"tags,omitempty"`
Template *types.CustomBool `json:"template,omitempty" url:"template,omitempty,int"`
Template *types2.CustomBool `json:"template,omitempty" url:"template,omitempty,int"`
TTY *int `json:"tty,omitempty" url:"tty,omitempty"`
Unique *types.CustomBool `json:"unique,omitempty" url:"unique,omitempty,int"`
Unprivileged *types.CustomBool `json:"unprivileged,omitempty" url:"unprivileged,omitempty,int"`
Unique *types2.CustomBool `json:"unique,omitempty" url:"unique,omitempty,int"`
Unprivileged *types2.CustomBool `json:"unprivileged,omitempty" url:"unprivileged,omitempty,int"`
VMID *int `json:"vmid,omitempty" url:"vmid,omitempty"`
}
// CustomFeatures contains the values for the "features" property.
type CustomFeatures struct {
FUSE *types.CustomBool `json:"fuse,omitempty" url:"fuse,omitempty,int"`
KeyControl *types.CustomBool `json:"keyctl,omitempty" url:"keyctl,omitempty,int"`
MountTypes *[]string `json:"mount,omitempty" url:"mount,omitempty"`
Nesting *types.CustomBool `json:"nesting,omitempty" url:"nesting,omitempty,int"`
FUSE *types2.CustomBool `json:"fuse,omitempty" url:"fuse,omitempty,int"`
KeyControl *types2.CustomBool `json:"keyctl,omitempty" url:"keyctl,omitempty,int"`
MountTypes *[]string `json:"mount,omitempty" url:"mount,omitempty"`
Nesting *types2.CustomBool `json:"nesting,omitempty" url:"nesting,omitempty,int"`
}
// CustomMountPoint contains the values for the "mp[n]" properties.
type CustomMountPoint struct {
ACL *types.CustomBool `json:"acl,omitempty" url:"acl,omitempty,int"`
Backup *types.CustomBool `json:"backup,omitempty" url:"backup,omitempty,int"`
DiskSize *string `json:"size,omitempty" url:"size,omitempty"`
Enabled bool `json:"-" url:"-"`
MountOptions *[]string `json:"mountoptions,omitempty" url:"mountoptions,omitempty"`
MountPoint string `json:"mp" url:"mp"`
Quota *types.CustomBool `json:"quota,omitempty" url:"quota,omitempty,int"`
ReadOnly *types.CustomBool `json:"ro,omitempty" url:"ro,omitempty,int"`
Replicate *types.CustomBool `json:"replicate,omitempty" url:"replicate,omitempty,int"`
Shared *types.CustomBool `json:"shared,omitempty" url:"shared,omitempty,int"`
Volume string `json:"volume" url:"volume"`
ACL *types2.CustomBool `json:"acl,omitempty" url:"acl,omitempty,int"`
Backup *types2.CustomBool `json:"backup,omitempty" url:"backup,omitempty,int"`
DiskSize *string `json:"size,omitempty" url:"size,omitempty"`
Enabled bool `json:"-" url:"-"`
MountOptions *[]string `json:"mountoptions,omitempty" url:"mountoptions,omitempty"`
MountPoint string `json:"mp" url:"mp"`
Quota *types2.CustomBool `json:"quota,omitempty" url:"quota,omitempty,int"`
ReadOnly *types2.CustomBool `json:"ro,omitempty" url:"ro,omitempty,int"`
Replicate *types2.CustomBool `json:"replicate,omitempty" url:"replicate,omitempty,int"`
Shared *types2.CustomBool `json:"shared,omitempty" url:"shared,omitempty,int"`
Volume string `json:"volume" url:"volume"`
}
// CustomMountPointArray is an array of CustomMountPoint.
@ -100,20 +101,20 @@ type CustomMountPointArray []CustomMountPoint
// CustomNetworkInterface contains the values for the "net[n]" properties.
type CustomNetworkInterface struct {
Bridge *string `json:"bridge,omitempty" url:"bridge,omitempty"`
Enabled bool `json:"-" url:"-"`
Firewall *types.CustomBool `json:"firewall,omitempty" url:"firewall,omitempty,int"`
IPv4Address *string `json:"ip,omitempty" url:"ip,omitempty"`
IPv4Gateway *string `json:"gw,omitempty" url:"gw,omitempty"`
IPv6Address *string `json:"ip6,omitempty" url:"ip6,omitempty"`
IPv6Gateway *string `json:"gw6,omitempty" url:"gw6,omitempty"`
MACAddress *string `json:"hwaddr,omitempty" url:"hwaddr,omitempty"`
MTU *int `json:"mtu,omitempty" url:"mtu,omitempty"`
Name string `json:"name" url:"name"`
RateLimit *float64 `json:"rate,omitempty" url:"rate,omitempty"`
Tag *int `json:"tag,omitempty" url:"tag,omitempty"`
Trunks *[]int `json:"trunks,omitempty" url:"trunks,omitempty"`
Type *string `json:"type,omitempty" url:"type,omitempty"`
Bridge *string `json:"bridge,omitempty" url:"bridge,omitempty"`
Enabled bool `json:"-" url:"-"`
Firewall *types2.CustomBool `json:"firewall,omitempty" url:"firewall,omitempty,int"`
IPv4Address *string `json:"ip,omitempty" url:"ip,omitempty"`
IPv4Gateway *string `json:"gw,omitempty" url:"gw,omitempty"`
IPv6Address *string `json:"ip6,omitempty" url:"ip6,omitempty"`
IPv6Gateway *string `json:"gw6,omitempty" url:"gw6,omitempty"`
MACAddress *string `json:"hwaddr,omitempty" url:"hwaddr,omitempty"`
MTU *int `json:"mtu,omitempty" url:"mtu,omitempty"`
Name string `json:"name" url:"name"`
RateLimit *float64 `json:"rate,omitempty" url:"rate,omitempty"`
Tag *int `json:"tag,omitempty" url:"tag,omitempty"`
Trunks *[]int `json:"trunks,omitempty" url:"trunks,omitempty"`
Type *string `json:"type,omitempty" url:"type,omitempty"`
}
// CustomNetworkInterfaceArray is an array of CustomNetworkInterface.
@ -121,14 +122,14 @@ type CustomNetworkInterfaceArray []CustomNetworkInterface
// CustomRootFS contains the values for the "rootfs" property.
type CustomRootFS struct {
ACL *types.CustomBool `json:"acl,omitempty" url:"acl,omitempty,int"`
Size *types.DiskSize `json:"size,omitempty" url:"size,omitempty"`
MountOptions *[]string `json:"mountoptions,omitempty" url:"mountoptions,omitempty"`
Quota *types.CustomBool `json:"quota,omitempty" url:"quota,omitempty,int"`
ReadOnly *types.CustomBool `json:"ro,omitempty" url:"ro,omitempty,int"`
Replicate *types.CustomBool `json:"replicate,omitempty" url:"replicate,omitempty,int"`
Shared *types.CustomBool `json:"shared,omitempty" url:"shared,omitempty,int"`
Volume string `json:"volume" url:"volume"`
ACL *types2.CustomBool `json:"acl,omitempty" url:"acl,omitempty,int"`
Size *types.DiskSize `json:"size,omitempty" url:"size,omitempty"`
MountOptions *[]string `json:"mountoptions,omitempty" url:"mountoptions,omitempty"`
Quota *types2.CustomBool `json:"quota,omitempty" url:"quota,omitempty,int"`
ReadOnly *types2.CustomBool `json:"ro,omitempty" url:"ro,omitempty,int"`
Replicate *types2.CustomBool `json:"replicate,omitempty" url:"replicate,omitempty,int"`
Shared *types2.CustomBool `json:"shared,omitempty" url:"shared,omitempty,int"`
Volume string `json:"volume" url:"volume"`
}
// CustomSSHKeys contains the values for the "ssh-public-keys" property.
@ -148,7 +149,7 @@ type GetResponseBody struct {
// GetResponseData contains the data from a user get response.
type GetResponseData struct {
ConsoleEnabled *types.CustomBool `json:"console,omitempty"`
ConsoleEnabled *types2.CustomBool `json:"console,omitempty"`
ConsoleMode *string `json:"cmode,omitempty"`
CPUArchitecture *string `json:"arch,omitempty"`
CPUCores *int `json:"cores,omitempty"`
@ -162,7 +163,7 @@ type GetResponseData struct {
Features *CustomFeatures `json:"features,omitempty"`
HookScript *string `json:"hookscript,omitempty"`
Hostname *string `json:"hostname,omitempty"`
Lock *types.CustomBool `json:"lock,omitempty"`
Lock *types2.CustomBool `json:"lock,omitempty"`
LXCConfiguration *[][2]string `json:"lxc,omitempty"`
MountPoint0 CustomMountPoint `json:"mp0,omitempty"`
MountPoint1 CustomMountPoint `json:"mp1,omitempty"`
@ -177,15 +178,15 @@ type GetResponseData struct {
NetworkInterface6 *CustomNetworkInterface `json:"net6,omitempty"`
NetworkInterface7 *CustomNetworkInterface `json:"net7,omitempty"`
OSType *string `json:"ostype,omitempty"`
Protection *types.CustomBool `json:"protection,omitempty"`
Protection *types2.CustomBool `json:"protection,omitempty"`
RootFS *CustomRootFS `json:"rootfs,omitempty"`
StartOnBoot *types.CustomBool `json:"onboot,omitempty"`
StartOnBoot *types2.CustomBool `json:"onboot,omitempty"`
StartupBehavior *CustomStartupBehavior `json:"startup,omitempty"`
Swap *int `json:"swap,omitempty"`
Tags *string `json:"tags,omitempty"`
Template *types.CustomBool `json:"template,omitempty"`
Template *types2.CustomBool `json:"template,omitempty"`
TTY *int `json:"tty,omitempty"`
Unprivileged *types.CustomBool `json:"unprivileged,omitempty"`
Unprivileged *types2.CustomBool `json:"unprivileged,omitempty"`
}
// GetStatusResponseBody contains the body from a container get status response.
@ -214,8 +215,8 @@ type RebootRequestBody struct {
// ShutdownRequestBody contains the body for a container shutdown request.
type ShutdownRequestBody struct {
ForceStop *types.CustomBool `json:"forceStop,omitempty" url:"forceStop,omitempty,int"`
Timeout *int `json:"timeout,omitempty" url:"timeout,omitempty"`
ForceStop *types2.CustomBool `json:"forceStop,omitempty" url:"forceStop,omitempty,int"`
Timeout *int `json:"timeout,omitempty" url:"timeout,omitempty"`
}
// UpdateRequestBody contains the data for an user update request.
@ -550,10 +551,10 @@ func (r *CustomFeatures) UnmarshalJSON(b []byte) error {
if len(v) == 2 {
switch v[0] {
case "fuse":
bv := types.CustomBool(v[1] == "1")
bv := types2.CustomBool(v[1] == "1")
r.FUSE = &bv
case "keyctl":
bv := types.CustomBool(v[1] == "1")
bv := types2.CustomBool(v[1] == "1")
r.KeyControl = &bv
case "mount":
if v[1] != "" {
@ -564,7 +565,7 @@ func (r *CustomFeatures) UnmarshalJSON(b []byte) error {
r.MountTypes = &a
}
case "nesting":
bv := types.CustomBool(v[1] == "1")
bv := types2.CustomBool(v[1] == "1")
r.Nesting = &bv
}
}
@ -592,10 +593,10 @@ func (r *CustomMountPoint) UnmarshalJSON(b []byte) error {
} else if len(v) == 2 {
switch v[0] {
case "acl":
bv := types.CustomBool(v[1] == "1")
bv := types2.CustomBool(v[1] == "1")
r.ACL = &bv
case "backup":
bv := types.CustomBool(v[1] == "1")
bv := types2.CustomBool(v[1] == "1")
r.Backup = &bv
case "mountoptions":
if v[1] != "" {
@ -608,16 +609,16 @@ func (r *CustomMountPoint) UnmarshalJSON(b []byte) error {
case "mp":
r.MountPoint = v[1]
case "quota":
bv := types.CustomBool(v[1] == "1")
bv := types2.CustomBool(v[1] == "1")
r.Quota = &bv
case "ro":
bv := types.CustomBool(v[1] == "1")
bv := types2.CustomBool(v[1] == "1")
r.ReadOnly = &bv
case "replicate":
bv := types.CustomBool(v[1] == "1")
bv := types2.CustomBool(v[1] == "1")
r.Replicate = &bv
case "shared":
bv := types.CustomBool(v[1] == "1")
bv := types2.CustomBool(v[1] == "1")
r.Shared = &bv
case "size":
r.DiskSize = &v[1]
@ -650,7 +651,7 @@ func (r *CustomNetworkInterface) UnmarshalJSON(b []byte) error {
case "bridge":
r.Bridge = &v[1]
case "firewall":
bv := types.CustomBool(v[1] == "1")
bv := types2.CustomBool(v[1] == "1")
r.Firewall = &bv
case "gw":
r.IPv4Gateway = &v[1]
@ -731,7 +732,7 @@ func (r *CustomRootFS) UnmarshalJSON(b []byte) error {
} else if len(v) == 2 {
switch v[0] {
case "acl":
bv := types.CustomBool(v[1] == "1")
bv := types2.CustomBool(v[1] == "1")
r.ACL = &bv
case "mountoptions":
if v[1] != "" {
@ -742,16 +743,16 @@ func (r *CustomRootFS) UnmarshalJSON(b []byte) error {
r.MountOptions = &a
}
case "quota":
bv := types.CustomBool(v[1] == "1")
bv := types2.CustomBool(v[1] == "1")
r.Quota = &bv
case "ro":
bv := types.CustomBool(v[1] == "1")
bv := types2.CustomBool(v[1] == "1")
r.ReadOnly = &bv
case "replicate":
bv := types.CustomBool(v[1] == "1")
bv := types2.CustomBool(v[1] == "1")
r.Replicate = &bv
case "shared":
bv := types.CustomBool(v[1] == "1")
bv := types2.CustomBool(v[1] == "1")
r.Shared = &bv
case "size":
r.Size = new(types.DiskSize)

125
proxmox/nodes/network.go Normal file
View File

@ -0,0 +1,125 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package nodes
import (
"context"
"fmt"
"net/http"
"net/url"
"sort"
"github.com/bpg/terraform-provider-proxmox/proxmox/api"
)
const (
networkReloadTimeoutSec = 5
)
// ListNetworkInterfaces retrieves a list of network interfaces for a specific nodes.
func (c *Client) ListNetworkInterfaces(ctx context.Context) ([]*NetworkInterfaceListResponseData, error) {
resBody := &NetworkInterfaceListResponseBody{}
err := c.DoRequest(ctx, http.MethodGet, c.ExpandPath("network"), nil, resBody)
if err != nil {
return nil, fmt.Errorf("failed to get network interfaces for node \"%s\": %w", c.NodeName, err)
}
if resBody.Data == nil {
return nil, api.ErrNoDataObjectInResponse
}
sort.Slice(resBody.Data, func(i, j int) bool {
return resBody.Data[i].Priority < resBody.Data[j].Priority
})
return resBody.Data, nil
}
// CreateNetworkInterface creates a network interface for a specific node.
func (c *Client) CreateNetworkInterface(ctx context.Context, d *NetworkInterfaceCreateUpdateRequestBody) error {
err := c.DoRequest(ctx, http.MethodPost, c.ExpandPath("network"), d, nil)
if err != nil {
return fmt.Errorf(
"failed to create network interface \"%s\" for node \"%s\": %w",
d.Iface, c.NodeName, err,
)
}
return nil
}
// ReloadNetworkConfiguration reloads the network configuration for a specific node.
func (c *Client) ReloadNetworkConfiguration(ctx context.Context) error {
resBody := &ReloadNetworkResponseBody{}
err := c.DoRequest(ctx, http.MethodPut, c.ExpandPath("network"), nil, resBody)
if err != nil {
return fmt.Errorf("failed to reload network configuration for node \"%s\": %w", c.NodeName, err)
}
if resBody.Data == nil {
return api.ErrNoDataObjectInResponse
}
err = c.Tasks().WaitForTask(ctx, *resBody.Data, networkReloadTimeoutSec, 1)
if err == nil {
return nil
}
return nil
}
// RevertNetworkConfiguration reverts the network configuration changes for a specific node.
func (c *Client) RevertNetworkConfiguration(ctx context.Context) error {
err := c.DoRequest(ctx, http.MethodDelete, c.ExpandPath("network"), nil, nil)
if err != nil {
return fmt.Errorf("failed to revert network configuration for node \"%s\": %w", c.NodeName, err)
}
return nil
}
// UpdateNetworkInterface updates a network interface for a specific node.
func (c *Client) UpdateNetworkInterface(
ctx context.Context,
iface string,
d *NetworkInterfaceCreateUpdateRequestBody,
) error {
err := c.DoRequest(
ctx,
http.MethodPut,
c.ExpandPath(fmt.Sprintf("network/%s", url.PathEscape(iface))),
d,
nil,
)
if err != nil {
return fmt.Errorf("failed to update network interface \"%s\" for node \"%s\": %w",
d.Iface, c.NodeName, err,
)
}
return nil
}
// DeleteNetworkInterface deletes a network interface configuration for a specific node.
func (c *Client) DeleteNetworkInterface(ctx context.Context, iface string) error {
err := c.DoRequest(
ctx,
http.MethodDelete,
c.ExpandPath(fmt.Sprintf("network/%s", url.PathEscape(iface))),
nil,
nil,
)
if err != nil {
return fmt.Errorf("failed to delete network interface \"%s\" for node \"%s\": %w",
iface, c.NodeName, err,
)
}
return nil
}

View File

@ -0,0 +1,83 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package nodes
import (
"github.com/bpg/terraform-provider-proxmox/internal/types"
)
// NetworkInterfaceListResponseBody contains the body from a node network interface list response.
type NetworkInterfaceListResponseBody struct {
Data []*NetworkInterfaceListResponseData `json:"data,omitempty"`
}
// NetworkInterfaceListResponseData contains the data from a node network interface list response.
type NetworkInterfaceListResponseData struct {
Active *types.CustomBool `json:"active,omitempty"`
Address *string `json:"address,omitempty"`
Address6 *string `json:"address6,omitempty"`
Autostart *types.CustomBool `json:"autostart,omitempty"`
BridgeFD *string `json:"bridge_fd,omitempty"`
BridgePorts *string `json:"bridge_ports,omitempty"`
BridgeSTP *string `json:"bridge_stp,omitempty"`
BridgeVIDs *string `json:"bridge_vids,omitempty"`
BridgeVLANAware *types.CustomBool `json:"bridge_vlan_aware,omitempty"`
CIDR *string `json:"cidr,omitempty"`
CIDR6 *string `json:"cidr6,omitempty"`
Comments *string `json:"comments,omitempty"`
Exists *types.CustomBool `json:"exists,omitempty"`
Families *[]string `json:"families,omitempty"`
Gateway *string `json:"gateway,omitempty"`
Gateway6 *string `json:"gateway6,omitempty"`
Iface string `json:"iface"`
MethodIPv4 *string `json:"method,omitempty"`
MethodIPv6 *string `json:"method6,omitempty"`
MTU *string `json:"mtu,omitempty"`
Netmask *string `json:"netmask,omitempty"`
VLANID *string `json:"vlan-id,omitempty"`
VLANRawDevice *string `json:"vlan-raw-device,omitempty"`
Priority int `json:"priority"`
Type string `json:"type"`
}
// NetworkInterfaceCreateUpdateRequestBody contains the body for a node network interface create / update request.
type NetworkInterfaceCreateUpdateRequestBody struct {
Iface string `json:"iface" url:"iface"`
Type string `json:"type" url:"type"`
Address *string `json:"address,omitempty" url:"address,omitempty"`
Address6 *string `json:"address6,omitempty" url:"address6,omitempty"`
Autostart *types.CustomBool `json:"autostart,omitempty" url:"autostart,omitempty,int"`
BondPrimary *string `json:"bond-primary,omitempty" url:"bond-primary,omitempty"`
BondMode *string `json:"bond_mode,omitempty" url:"bond_mode,omitempty"`
BondXmitHashPolicy *string `json:"bond_xmit_hash_policy,omitempty" url:"bond_xmit_hash_policy,omitempty"`
BridgePorts *string `json:"bridge_ports,omitempty" url:"bridge_ports,omitempty"`
BridgeVLANAware *types.CustomBool `json:"bridge_vlan_aware,omitempty" url:"bridge_vlan_aware,omitempty,int"`
CIDR *string `json:"cidr,omitempty" url:"cidr,omitempty"`
CIDR6 *string `json:"cidr6,omitempty" url:"cidr6,omitempty"`
Comments *string `json:"comments,omitempty" url:"comments,omitempty"`
Comments6 *string `json:"comments6,omitempty" url:"comments6,omitempty"`
Gateway *string `json:"gateway,omitempty" url:"gateway,omitempty"`
Gateway6 *string `json:"gateway6,omitempty" url:"gateway6,omitempty"`
Delete *[]string `json:"delete,omitempty" url:"delete,omitempty"`
MTU *int64 `json:"mtu,omitempty" url:"mtu,omitempty"`
Netmask *string `json:"netmask,omitempty" url:"netmask,omitempty"`
Netmask6 *string `json:"netmask6,omitempty" url:"netmask6,omitempty"`
OVSBonds *string `json:"ovs_bonds,omitempty" url:"ovs_bonds,omitempty"`
OVSBridge *string `json:"ovs_bridge,omitempty" url:"ovs_bridge,omitempty"`
OVSOptions *string `json:"ovs_options,omitempty" url:"ovs_options,omitempty"`
OVSPorts *string `json:"ovs_ports,omitempty" url:"ovs_ports,omitempty"`
OVSTag *string `json:"ovs_tag,omitempty" url:"ovs_tag,omitempty"`
Slaves *string `json:"slaves,omitempty" url:"slaves,omitempty"`
VLANID *int64 `json:"vlan_id,omitempty" url:"vlan_id,omitempty"`
VLANRawDevice *string `json:"vlan-raw-device,omitempty" url:"vlan-raw-device,omitempty"`
}
// ReloadNetworkResponseBody contains the body from a node network reload response.
type ReloadNetworkResponseBody struct {
Data *string `json:"data,omitempty"`
}

View File

@ -11,72 +11,10 @@ import (
"fmt"
"net/http"
"sort"
"strings"
"github.com/bpg/terraform-provider-proxmox/proxmox/api"
)
// GetIP retrieves the IP address of a node.
func (c *Client) GetIP(ctx context.Context) (string, error) {
networkDevices, err := c.ListNetworkDevices(ctx)
if err != nil {
return "", err
}
nodeAddress := ""
for _, d := range networkDevices {
if d.Address != nil {
nodeAddress = *d.Address
break
}
}
if nodeAddress == "" {
return "", fmt.Errorf("failed to determine the IP address of node \"%s\"", c.NodeName)
}
nodeAddressParts := strings.Split(nodeAddress, "/")
return nodeAddressParts[0], nil
}
// GetTime retrieves the time information for a node.
func (c *Client) GetTime(ctx context.Context) (*GetTimeResponseData, error) {
resBody := &GetTimeResponseBody{}
err := c.DoRequest(ctx, http.MethodGet, c.ExpandPath("time"), nil, resBody)
if err != nil {
return nil, fmt.Errorf("failed to get time information for node \"%s\": %w", c.NodeName, err)
}
if resBody.Data == nil {
return nil, api.ErrNoDataObjectInResponse
}
return resBody.Data, nil
}
// ListNetworkDevices retrieves a list of network devices for a specific nodes.
func (c *Client) ListNetworkDevices(ctx context.Context) ([]*NetworkDeviceListResponseData, error) {
resBody := &NetworkDeviceListResponseBody{}
err := c.DoRequest(ctx, http.MethodGet, c.ExpandPath("network"), nil, resBody)
if err != nil {
return nil, fmt.Errorf("failed to get network devices for node \"%s\": %w", c.NodeName, err)
}
if resBody.Data == nil {
return nil, api.ErrNoDataObjectInResponse
}
sort.Slice(resBody.Data, func(i, j int) bool {
return resBody.Data[i].Priority < resBody.Data[j].Priority
})
return resBody.Data, nil
}
// ListNodes retrieves a list of nodes.
func (c *Client) ListNodes(ctx context.Context) ([]*ListResponseData, error) {
resBody := &ListResponseBody{}
@ -97,6 +35,22 @@ func (c *Client) ListNodes(ctx context.Context) ([]*ListResponseData, error) {
return resBody.Data, nil
}
// GetTime retrieves the time information for a node.
func (c *Client) GetTime(ctx context.Context) (*GetTimeResponseData, error) {
resBody := &GetTimeResponseBody{}
err := c.DoRequest(ctx, http.MethodGet, c.ExpandPath("time"), nil, resBody)
if err != nil {
return nil, fmt.Errorf("failed to get time information for node \"%s\": %w", c.NodeName, err)
}
if resBody.Data == nil {
return nil, api.ErrNoDataObjectInResponse
}
return resBody.Data, nil
}
// UpdateTime updates the time on a node.
func (c *Client) UpdateTime(ctx context.Context, d *UpdateTimeRequestBody) error {
err := c.DoRequest(ctx, http.MethodPut, c.ExpandPath("time"), d, nil)

View File

@ -11,7 +11,7 @@ import (
"fmt"
"net/url"
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
"github.com/bpg/terraform-provider-proxmox/internal/types"
)
// CustomCommands contains an array of commands to execute.
@ -52,31 +52,6 @@ type ListResponseData struct {
Uptime *int `json:"uptime"`
}
// NetworkDeviceListResponseBody contains the body from a node network device list response.
type NetworkDeviceListResponseBody struct {
Data []*NetworkDeviceListResponseData `json:"data,omitempty"`
}
// NetworkDeviceListResponseData contains the data from a node network device list response.
type NetworkDeviceListResponseData struct {
Active *types.CustomBool `json:"active,omitempty"`
Address *string `json:"address,omitempty"`
Autostart *types.CustomBool `json:"autostart,omitempty"`
BridgeFD *string `json:"bridge_fd,omitempty"`
BridgePorts *string `json:"bridge_ports,omitempty"`
BridgeSTP *string `json:"bridge_stp,omitempty"`
CIDR *string `json:"cidr,omitempty"`
Exists *types.CustomBool `json:"exists,omitempty"`
Families *[]string `json:"families,omitempty"`
Gateway *string `json:"gateway,omitempty"`
Iface string `json:"iface"`
MethodIPv4 *string `json:"method,omitempty"`
MethodIPv6 *string `json:"method6,omitempty"`
Netmask *string `json:"netmask,omitempty"`
Priority int `json:"priority"`
Type string `json:"type"`
}
// UpdateTimeRequestBody contains the body for a node time update request.
type UpdateTimeRequestBody struct {
TimeZone string `json:"timezone" url:"timezone"`

View File

@ -7,7 +7,7 @@
package nodes
import (
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
"github.com/bpg/terraform-provider-proxmox/internal/types"
)
// DatastoreFileListResponseBody contains the body from a datastore content list response.

View File

@ -39,9 +39,9 @@ func (c *Client) GetTaskStatus(ctx context.Context, upid string) (*GetTaskStatus
}
// WaitForTask waits for a specific task to complete.
func (c *Client) WaitForTask(ctx context.Context, upid string, timeout, delay int) error {
timeDelay := int64(delay)
timeMax := float64(timeout)
func (c *Client) WaitForTask(ctx context.Context, upid string, timeoutSec, delaySec int) error {
timeDelay := int64(delaySec)
timeMax := float64(timeoutSec)
timeStart := time.Now()
timeElapsed := timeStart.Sub(timeStart)
@ -80,7 +80,7 @@ func (c *Client) WaitForTask(ctx context.Context, upid string, timeout, delay in
}
return fmt.Errorf(
"timeout while waiting for task \"%s\" to complete",
"timeoutSec while waiting for task \"%s\" to complete",
upid,
)
}

View File

@ -15,14 +15,15 @@ import (
"strconv"
"strings"
types2 "github.com/bpg/terraform-provider-proxmox/internal/types"
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
)
// CustomAgent handles QEMU agent parameters.
type CustomAgent struct {
Enabled *types.CustomBool `json:"enabled,omitempty" url:"enabled,int"`
TrimClonedDisks *types.CustomBool `json:"fstrim_cloned_disks" url:"fstrim_cloned_disks,int"`
Type *string `json:"type" url:"type"`
Enabled *types2.CustomBool `json:"enabled,omitempty" url:"enabled,int"`
TrimClonedDisks *types2.CustomBool `json:"fstrim_cloned_disks" url:"fstrim_cloned_disks,int"`
Type *string `json:"type" url:"type"`
}
// CustomAudioDevice handles QEMU audio parameters.
@ -73,10 +74,10 @@ type CustomCloudInitSSHKeys []string
// CustomCPUEmulation handles QEMU CPU emulation parameters.
type CustomCPUEmulation struct {
Flags *[]string `json:"flags,omitempty" url:"flags,omitempty,semicolon"`
Hidden *types.CustomBool `json:"hidden,omitempty" url:"hidden,omitempty,int"`
HVVendorID *string `json:"hv-vendor-id,omitempty" url:"hv-vendor-id,omitempty"`
Type string `json:"cputype,omitempty" url:"cputype,omitempty"`
Flags *[]string `json:"flags,omitempty" url:"flags,omitempty,semicolon"`
Hidden *types2.CustomBool `json:"hidden,omitempty" url:"hidden,omitempty,int"`
HVVendorID *string `json:"hv-vendor-id,omitempty" url:"hv-vendor-id,omitempty"`
Type string `json:"cputype,omitempty" url:"cputype,omitempty"`
}
// CustomEFIDisk handles QEMU EFI disk parameters.
@ -88,17 +89,17 @@ type CustomEFIDisk struct {
// CustomNetworkDevice handles QEMU network device parameters.
type CustomNetworkDevice struct {
Model string `json:"model" url:"model"`
Bridge *string `json:"bridge,omitempty" url:"bridge,omitempty"`
Enabled bool `json:"-" url:"-"`
Firewall *types.CustomBool `json:"firewall,omitempty" url:"firewall,omitempty,int"`
LinkDown *types.CustomBool `json:"link_down,omitempty" url:"link_down,omitempty,int"`
MACAddress *string `json:"macaddr,omitempty" url:"macaddr,omitempty"`
Queues *int `json:"queues,omitempty" url:"queues,omitempty"`
RateLimit *float64 `json:"rate,omitempty" url:"rate,omitempty"`
Tag *int `json:"tag,omitempty" url:"tag,omitempty"`
MTU *int `json:"mtu,omitempty" url:"mtu,omitempty"`
Trunks []int `json:"trunks,omitempty" url:"trunks,omitempty"`
Model string `json:"model" url:"model"`
Bridge *string `json:"bridge,omitempty" url:"bridge,omitempty"`
Enabled bool `json:"-" url:"-"`
Firewall *types2.CustomBool `json:"firewall,omitempty" url:"firewall,omitempty,int"`
LinkDown *types2.CustomBool `json:"link_down,omitempty" url:"link_down,omitempty,int"`
MACAddress *string `json:"macaddr,omitempty" url:"macaddr,omitempty"`
Queues *int `json:"queues,omitempty" url:"queues,omitempty"`
RateLimit *float64 `json:"rate,omitempty" url:"rate,omitempty"`
Tag *int `json:"tag,omitempty" url:"tag,omitempty"`
MTU *int `json:"mtu,omitempty" url:"mtu,omitempty"`
Trunks []int `json:"trunks,omitempty" url:"trunks,omitempty"`
}
// CustomNetworkDevices handles QEMU network device parameters.
@ -117,12 +118,12 @@ type CustomNUMADevices []CustomNUMADevice
// CustomPCIDevice handles QEMU host PCI device mapping parameters.
type CustomPCIDevice struct {
DeviceIDs []string `json:"host" url:"host,semicolon"`
MDev *string `json:"mdev,omitempty" url:"mdev,omitempty"`
PCIExpress *types.CustomBool `json:"pcie,omitempty" url:"pcie,omitempty,int"`
ROMBAR *types.CustomBool `json:"rombar,omitempty" url:"rombar,omitempty,int"`
ROMFile *string `json:"romfile,omitempty" url:"romfile,omitempty"`
XVGA *types.CustomBool `json:"x-vga,omitempty" url:"x-vga,omitempty,int"`
DeviceIDs []string `json:"host" url:"host,semicolon"`
MDev *string `json:"mdev,omitempty" url:"mdev,omitempty"`
PCIExpress *types2.CustomBool `json:"pcie,omitempty" url:"pcie,omitempty,int"`
ROMBAR *types2.CustomBool `json:"rombar,omitempty" url:"rombar,omitempty,int"`
ROMFile *string `json:"romfile,omitempty" url:"romfile,omitempty"`
XVGA *types2.CustomBool `json:"x-vga,omitempty" url:"x-vga,omitempty,int"`
}
// CustomPCIDevices handles QEMU host PCI device mapping parameters.
@ -139,20 +140,20 @@ type CustomSharedMemory struct {
// CustomSMBIOS handles QEMU SMBIOS parameters.
type CustomSMBIOS struct {
Base64 *types.CustomBool `json:"base64,omitempty" url:"base64,omitempty"`
Family *string `json:"family,omitempty" url:"family,omitempty"`
Manufacturer *string `json:"manufacturer,omitempty" url:"manufacturer,omitempty"`
Product *string `json:"product,omitempty" url:"product,omitempty"`
Serial *string `json:"serial,omitempty" url:"serial,omitempty"`
SKU *string `json:"sku,omitempty" url:"sku,omitempty"`
UUID *string `json:"uuid,omitempty" url:"uuid,omitempty"`
Version *string `json:"version,omitempty" url:"version,omitempty"`
Base64 *types2.CustomBool `json:"base64,omitempty" url:"base64,omitempty"`
Family *string `json:"family,omitempty" url:"family,omitempty"`
Manufacturer *string `json:"manufacturer,omitempty" url:"manufacturer,omitempty"`
Product *string `json:"product,omitempty" url:"product,omitempty"`
Serial *string `json:"serial,omitempty" url:"serial,omitempty"`
SKU *string `json:"sku,omitempty" url:"sku,omitempty"`
UUID *string `json:"uuid,omitempty" url:"uuid,omitempty"`
Version *string `json:"version,omitempty" url:"version,omitempty"`
}
// CustomSpiceEnhancements handles QEMU spice enhancement parameters.
type CustomSpiceEnhancements struct {
FolderSharing *types.CustomBool `json:"foldersharing,omitempty" url:"foldersharing,omitempty"`
VideoStreaming *string `json:"videostreaming,omitempty" url:"videostreaming,omitempty"`
FolderSharing *types2.CustomBool `json:"foldersharing,omitempty" url:"foldersharing,omitempty"`
VideoStreaming *string `json:"videostreaming,omitempty" url:"videostreaming,omitempty"`
}
// CustomStartupOrder handles QEMU startup order parameters.
@ -164,20 +165,20 @@ type CustomStartupOrder struct {
// CustomStorageDevice handles QEMU SATA device parameters.
type CustomStorageDevice struct {
AIO *string `json:"aio,omitempty" url:"aio,omitempty"`
BackupEnabled *types.CustomBool `json:"backup,omitempty" url:"backup,omitempty,int"`
BurstableReadSpeedMbps *int `json:"mbps_rd_max,omitempty" url:"mbps_rd_max,omitempty"`
BurstableWriteSpeedMbps *int `json:"mbps_wr_max,omitempty" url:"mbps_wr_max,omitempty"`
Discard *string `json:"discard,omitempty" url:"discard,omitempty"`
Enabled bool `json:"-" url:"-"`
FileVolume string `json:"file" url:"file"`
Format *string `json:"format,omitempty" url:"format,omitempty"`
IOThread *types.CustomBool `json:"iothread,omitempty" url:"iothread,omitempty,int"`
SSD *types.CustomBool `json:"ssd,omitempty" url:"ssd,omitempty,int"`
MaxReadSpeedMbps *int `json:"mbps_rd,omitempty" url:"mbps_rd,omitempty"`
MaxWriteSpeedMbps *int `json:"mbps_wr,omitempty" url:"mbps_wr,omitempty"`
Media *string `json:"media,omitempty" url:"media,omitempty"`
Size *types.DiskSize `json:"size,omitempty" url:"size,omitempty"`
AIO *string `json:"aio,omitempty" url:"aio,omitempty"`
BackupEnabled *types2.CustomBool `json:"backup,omitempty" url:"backup,omitempty,int"`
BurstableReadSpeedMbps *int `json:"mbps_rd_max,omitempty" url:"mbps_rd_max,omitempty"`
BurstableWriteSpeedMbps *int `json:"mbps_wr_max,omitempty" url:"mbps_wr_max,omitempty"`
Discard *string `json:"discard,omitempty" url:"discard,omitempty"`
Enabled bool `json:"-" url:"-"`
FileVolume string `json:"file" url:"file"`
Format *string `json:"format,omitempty" url:"format,omitempty"`
IOThread *types2.CustomBool `json:"iothread,omitempty" url:"iothread,omitempty,int"`
SSD *types2.CustomBool `json:"ssd,omitempty" url:"ssd,omitempty,int"`
MaxReadSpeedMbps *int `json:"mbps_rd,omitempty" url:"mbps_rd,omitempty"`
MaxWriteSpeedMbps *int `json:"mbps_wr,omitempty" url:"mbps_wr,omitempty"`
Media *string `json:"media,omitempty" url:"media,omitempty"`
Size *types.DiskSize `json:"size,omitempty" url:"size,omitempty"`
Interface *string
ID *string
FileID *string
@ -189,8 +190,8 @@ type CustomStorageDevices map[string]CustomStorageDevice
// CustomUSBDevice handles QEMU USB device parameters.
type CustomUSBDevice struct {
HostDevice string `json:"host" url:"host"`
USB3 *types.CustomBool `json:"usb3,omitempty" url:"usb3,omitempty,int"`
HostDevice string `json:"host" url:"host"`
USB3 *types2.CustomBool `json:"usb3,omitempty" url:"usb3,omitempty,int"`
}
// CustomUSBDevices handles QEMU USB device parameters.
@ -204,10 +205,10 @@ type CustomVGADevice struct {
// CustomVirtualIODevice handles QEMU VirtIO device parameters.
type CustomVirtualIODevice struct {
AIO *string `json:"aio,omitempty" url:"aio,omitempty"`
BackupEnabled *types.CustomBool `json:"backup,omitempty" url:"backup,omitempty,int"`
Enabled bool `json:"-" url:"-"`
FileVolume string `json:"file" url:"file"`
AIO *string `json:"aio,omitempty" url:"aio,omitempty"`
BackupEnabled *types2.CustomBool `json:"backup,omitempty" url:"backup,omitempty,int"`
Enabled bool `json:"-" url:"-"`
FileVolume string `json:"file" url:"file"`
}
// CustomVirtualIODevices handles QEMU VirtIO device parameters.
@ -221,89 +222,89 @@ type CustomWatchdogDevice struct {
// CloneRequestBody contains the data for an virtual machine clone request.
type CloneRequestBody struct {
BandwidthLimit *int `json:"bwlimit,omitempty" url:"bwlimit,omitempty"`
Description *string `json:"description,omitempty" url:"description,omitempty"`
FullCopy *types.CustomBool `json:"full,omitempty" url:"full,omitempty,int"`
Name *string `json:"name,omitempty" url:"name,omitempty"`
PoolID *string `json:"pool,omitempty" url:"pool,omitempty"`
SnapshotName *string `json:"snapname,omitempty" url:"snapname,omitempty"`
TargetNodeName *string `json:"target,omitempty" url:"target,omitempty"`
TargetStorage *string `json:"storage,omitempty" url:"storage,omitempty"`
TargetStorageFormat *string `json:"format,omitempty" url:"format,omitempty"`
VMIDNew int `json:"newid" url:"newid"`
BandwidthLimit *int `json:"bwlimit,omitempty" url:"bwlimit,omitempty"`
Description *string `json:"description,omitempty" url:"description,omitempty"`
FullCopy *types2.CustomBool `json:"full,omitempty" url:"full,omitempty,int"`
Name *string `json:"name,omitempty" url:"name,omitempty"`
PoolID *string `json:"pool,omitempty" url:"pool,omitempty"`
SnapshotName *string `json:"snapname,omitempty" url:"snapname,omitempty"`
TargetNodeName *string `json:"target,omitempty" url:"target,omitempty"`
TargetStorage *string `json:"storage,omitempty" url:"storage,omitempty"`
TargetStorageFormat *string `json:"format,omitempty" url:"format,omitempty"`
VMIDNew int `json:"newid" url:"newid"`
}
// CreateRequestBody contains the data for a virtual machine create request.
type CreateRequestBody struct {
ACPI *types.CustomBool `json:"acpi,omitempty" url:"acpi,omitempty,int"`
Agent *CustomAgent `json:"agent,omitempty" url:"agent,omitempty"`
AllowReboot *types.CustomBool `json:"reboot,omitempty" url:"reboot,omitempty,int"`
AudioDevices CustomAudioDevices `json:"audio,omitempty" url:"audio,omitempty"`
Autostart *types.CustomBool `json:"autostart,omitempty" url:"autostart,omitempty,int"`
BackupFile *string `json:"archive,omitempty" url:"archive,omitempty"`
BandwidthLimit *int `json:"bwlimit,omitempty" url:"bwlimit,omitempty"`
BIOS *string `json:"bios,omitempty" url:"bios,omitempty"`
Boot *CustomBoot `json:"boot,omitempty" url:"boot,omitempty"`
CDROM *string `json:"cdrom,omitempty" url:"cdrom,omitempty"`
CloudInitConfig *CustomCloudInitConfig `json:"cloudinit,omitempty" url:"cloudinit,omitempty"`
CPUArchitecture *string `json:"arch,omitempty" url:"arch,omitempty"`
CPUCores *int `json:"cores,omitempty" url:"cores,omitempty"`
CPUEmulation *CustomCPUEmulation `json:"cpu,omitempty" url:"cpu,omitempty"`
CPULimit *int `json:"cpulimit,omitempty" url:"cpulimit,omitempty"`
CPUSockets *int `json:"sockets,omitempty" url:"sockets,omitempty"`
CPUUnits *int `json:"cpuunits,omitempty" url:"cpuunits,omitempty"`
DedicatedMemory *int `json:"memory,omitempty" url:"memory,omitempty"`
Delete []string `json:"delete,omitempty" url:"delete,omitempty,comma"`
DeletionProtection *types.CustomBool `json:"protection,omitempty" url:"force,omitempty,int"`
Description *string `json:"description,omitempty" url:"description,omitempty"`
EFIDisk *CustomEFIDisk `json:"efidisk0,omitempty" url:"efidisk0,omitempty"`
FloatingMemory *int `json:"balloon,omitempty" url:"balloon,omitempty"`
FloatingMemoryShares *int `json:"shares,omitempty" url:"shares,omitempty"`
Freeze *types.CustomBool `json:"freeze,omitempty" url:"freeze,omitempty,int"`
HookScript *string `json:"hookscript,omitempty" url:"hookscript,omitempty"`
Hotplug types.CustomCommaSeparatedList `json:"hotplug,omitempty" url:"hotplug,omitempty,comma"`
Hugepages *string `json:"hugepages,omitempty" url:"hugepages,omitempty"`
IDEDevices CustomStorageDevices `json:"ide,omitempty" url:",omitempty"`
KeyboardLayout *string `json:"keyboard,omitempty" url:"keyboard,omitempty"`
KVMArguments *string `json:"args,omitempty" url:"args,omitempty,space"`
KVMEnabled *types.CustomBool `json:"kvm,omitempty" url:"kvm,omitempty,int"`
LocalTime *types.CustomBool `json:"localtime,omitempty" url:"localtime,omitempty,int"`
Lock *string `json:"lock,omitempty" url:"lock,omitempty"`
Machine *string `json:"machine,omitempty" url:"machine,omitempty"`
MigrateDowntime *float64 `json:"migrate_downtime,omitempty" url:"migrate_downtime,omitempty"`
MigrateSpeed *int `json:"migrate_speed,omitempty" url:"migrate_speed,omitempty"`
Name *string `json:"name,omitempty" url:"name,omitempty"`
NetworkDevices CustomNetworkDevices `json:"net,omitempty" url:"net,omitempty"`
NUMADevices CustomNUMADevices `json:"numa_devices,omitempty" url:"numa,omitempty"`
NUMAEnabled *types.CustomBool `json:"numa,omitempty" url:"numa,omitempty,int"`
OSType *string `json:"ostype,omitempty" url:"ostype,omitempty"`
Overwrite *types.CustomBool `json:"force,omitempty" url:"force,omitempty,int"`
PCIDevices CustomPCIDevices `json:"hostpci,omitempty" url:"hostpci,omitempty"`
PoolID *string `json:"pool,omitempty" url:"pool,omitempty"`
Revert *string `json:"revert,omitempty" url:"revert,omitempty"`
SATADevices CustomStorageDevices `json:"sata,omitempty" url:"sata,omitempty"`
SCSIDevices CustomStorageDevices `json:"scsi,omitempty" url:"scsi,omitempty"`
SCSIHardware *string `json:"scsihw,omitempty" url:"scsihw,omitempty"`
SerialDevices CustomSerialDevices `json:"serial,omitempty" url:"serial,omitempty"`
SharedMemory *CustomSharedMemory `json:"ivshmem,omitempty" url:"ivshmem,omitempty"`
SkipLock *types.CustomBool `json:"skiplock,omitempty" url:"skiplock,omitempty,int"`
SMBIOS *CustomSMBIOS `json:"smbios1,omitempty" url:"smbios1,omitempty"`
SpiceEnhancements *CustomSpiceEnhancements `json:"spice_enhancements,omitempty" url:"spice_enhancements,omitempty"`
StartDate *string `json:"startdate,omitempty" url:"startdate,omitempty"`
StartOnBoot *types.CustomBool `json:"onboot,omitempty" url:"onboot,omitempty,int"`
StartupOrder *CustomStartupOrder `json:"startup,omitempty" url:"startup,omitempty"`
TabletDeviceEnabled *types.CustomBool `json:"tablet,omitempty" url:"tablet,omitempty,int"`
Tags *string `json:"tags,omitempty" url:"tags,omitempty"`
Template *types.CustomBool `json:"template,omitempty" url:"template,omitempty,int"`
TimeDriftFixEnabled *types.CustomBool `json:"tdf,omitempty" url:"tdf,omitempty,int"`
USBDevices CustomUSBDevices `json:"usb,omitempty" url:"usb,omitempty"`
VGADevice *CustomVGADevice `json:"vga,omitempty" url:"vga,omitempty"`
VirtualCPUCount *int `json:"vcpus,omitempty" url:"vcpus,omitempty"`
VirtualIODevices CustomStorageDevices `json:"virtio,omitempty" url:"virtio,omitempty"`
VMGenerationID *string `json:"vmgenid,omitempty" url:"vmgenid,omitempty"`
VMID *int `json:"vmid,omitempty" url:"vmid,omitempty"`
VMStateDatastoreID *string `json:"vmstatestorage,omitempty" url:"vmstatestorage,omitempty"`
WatchdogDevice *CustomWatchdogDevice `json:"watchdog,omitempty" url:"watchdog,omitempty"`
ACPI *types2.CustomBool `json:"acpi,omitempty" url:"acpi,omitempty,int"`
Agent *CustomAgent `json:"agent,omitempty" url:"agent,omitempty"`
AllowReboot *types2.CustomBool `json:"reboot,omitempty" url:"reboot,omitempty,int"`
AudioDevices CustomAudioDevices `json:"audio,omitempty" url:"audio,omitempty"`
Autostart *types2.CustomBool `json:"autostart,omitempty" url:"autostart,omitempty,int"`
BackupFile *string `json:"archive,omitempty" url:"archive,omitempty"`
BandwidthLimit *int `json:"bwlimit,omitempty" url:"bwlimit,omitempty"`
BIOS *string `json:"bios,omitempty" url:"bios,omitempty"`
Boot *CustomBoot `json:"boot,omitempty" url:"boot,omitempty"`
CDROM *string `json:"cdrom,omitempty" url:"cdrom,omitempty"`
CloudInitConfig *CustomCloudInitConfig `json:"cloudinit,omitempty" url:"cloudinit,omitempty"`
CPUArchitecture *string `json:"arch,omitempty" url:"arch,omitempty"`
CPUCores *int `json:"cores,omitempty" url:"cores,omitempty"`
CPUEmulation *CustomCPUEmulation `json:"cpu,omitempty" url:"cpu,omitempty"`
CPULimit *int `json:"cpulimit,omitempty" url:"cpulimit,omitempty"`
CPUSockets *int `json:"sockets,omitempty" url:"sockets,omitempty"`
CPUUnits *int `json:"cpuunits,omitempty" url:"cpuunits,omitempty"`
DedicatedMemory *int `json:"memory,omitempty" url:"memory,omitempty"`
Delete []string `json:"delete,omitempty" url:"delete,omitempty,comma"`
DeletionProtection *types2.CustomBool `json:"protection,omitempty" url:"force,omitempty,int"`
Description *string `json:"description,omitempty" url:"description,omitempty"`
EFIDisk *CustomEFIDisk `json:"efidisk0,omitempty" url:"efidisk0,omitempty"`
FloatingMemory *int `json:"balloon,omitempty" url:"balloon,omitempty"`
FloatingMemoryShares *int `json:"shares,omitempty" url:"shares,omitempty"`
Freeze *types2.CustomBool `json:"freeze,omitempty" url:"freeze,omitempty,int"`
HookScript *string `json:"hookscript,omitempty" url:"hookscript,omitempty"`
Hotplug types2.CustomCommaSeparatedList `json:"hotplug,omitempty" url:"hotplug,omitempty,comma"`
Hugepages *string `json:"hugepages,omitempty" url:"hugepages,omitempty"`
IDEDevices CustomStorageDevices `json:"ide,omitempty" url:",omitempty"`
KeyboardLayout *string `json:"keyboard,omitempty" url:"keyboard,omitempty"`
KVMArguments *string `json:"args,omitempty" url:"args,omitempty,space"`
KVMEnabled *types2.CustomBool `json:"kvm,omitempty" url:"kvm,omitempty,int"`
LocalTime *types2.CustomBool `json:"localtime,omitempty" url:"localtime,omitempty,int"`
Lock *string `json:"lock,omitempty" url:"lock,omitempty"`
Machine *string `json:"machine,omitempty" url:"machine,omitempty"`
MigrateDowntime *float64 `json:"migrate_downtime,omitempty" url:"migrate_downtime,omitempty"`
MigrateSpeed *int `json:"migrate_speed,omitempty" url:"migrate_speed,omitempty"`
Name *string `json:"name,omitempty" url:"name,omitempty"`
NetworkDevices CustomNetworkDevices `json:"net,omitempty" url:"net,omitempty"`
NUMADevices CustomNUMADevices `json:"numa_devices,omitempty" url:"numa,omitempty"`
NUMAEnabled *types2.CustomBool `json:"numa,omitempty" url:"numa,omitempty,int"`
OSType *string `json:"ostype,omitempty" url:"ostype,omitempty"`
Overwrite *types2.CustomBool `json:"force,omitempty" url:"force,omitempty,int"`
PCIDevices CustomPCIDevices `json:"hostpci,omitempty" url:"hostpci,omitempty"`
PoolID *string `json:"pool,omitempty" url:"pool,omitempty"`
Revert *string `json:"revert,omitempty" url:"revert,omitempty"`
SATADevices CustomStorageDevices `json:"sata,omitempty" url:"sata,omitempty"`
SCSIDevices CustomStorageDevices `json:"scsi,omitempty" url:"scsi,omitempty"`
SCSIHardware *string `json:"scsihw,omitempty" url:"scsihw,omitempty"`
SerialDevices CustomSerialDevices `json:"serial,omitempty" url:"serial,omitempty"`
SharedMemory *CustomSharedMemory `json:"ivshmem,omitempty" url:"ivshmem,omitempty"`
SkipLock *types2.CustomBool `json:"skiplock,omitempty" url:"skiplock,omitempty,int"`
SMBIOS *CustomSMBIOS `json:"smbios1,omitempty" url:"smbios1,omitempty"`
SpiceEnhancements *CustomSpiceEnhancements `json:"spice_enhancements,omitempty" url:"spice_enhancements,omitempty"`
StartDate *string `json:"startdate,omitempty" url:"startdate,omitempty"`
StartOnBoot *types2.CustomBool `json:"onboot,omitempty" url:"onboot,omitempty,int"`
StartupOrder *CustomStartupOrder `json:"startup,omitempty" url:"startup,omitempty"`
TabletDeviceEnabled *types2.CustomBool `json:"tablet,omitempty" url:"tablet,omitempty,int"`
Tags *string `json:"tags,omitempty" url:"tags,omitempty"`
Template *types2.CustomBool `json:"template,omitempty" url:"template,omitempty,int"`
TimeDriftFixEnabled *types2.CustomBool `json:"tdf,omitempty" url:"tdf,omitempty,int"`
USBDevices CustomUSBDevices `json:"usb,omitempty" url:"usb,omitempty"`
VGADevice *CustomVGADevice `json:"vga,omitempty" url:"vga,omitempty"`
VirtualCPUCount *int `json:"vcpus,omitempty" url:"vcpus,omitempty"`
VirtualIODevices CustomStorageDevices `json:"virtio,omitempty" url:"virtio,omitempty"`
VMGenerationID *string `json:"vmgenid,omitempty" url:"vmgenid,omitempty"`
VMID *int `json:"vmid,omitempty" url:"vmid,omitempty"`
VMStateDatastoreID *string `json:"vmstatestorage,omitempty" url:"vmstatestorage,omitempty"`
WatchdogDevice *CustomWatchdogDevice `json:"watchdog,omitempty" url:"watchdog,omitempty"`
}
// CreateResponseBody contains the body from a create response.
@ -355,137 +356,137 @@ type GetResponseBody struct {
// GetResponseData contains the data from an virtual machine get response.
type GetResponseData struct {
ACPI *types.CustomBool `json:"acpi,omitempty"`
Agent *CustomAgent `json:"agent,omitempty"`
AllowReboot *types.CustomBool `json:"reboot,omitempty"`
AudioDevice *CustomAudioDevice `json:"audio0,omitempty"`
Autostart *types.CustomBool `json:"autostart,omitempty"`
BackupFile *string `json:"archive,omitempty"`
BandwidthLimit *int `json:"bwlimit,omitempty"`
BIOS *string `json:"bios,omitempty"`
BootDisk *string `json:"bootdisk,omitempty"`
BootOrder *string `json:"boot,omitempty"`
CDROM *string `json:"cdrom,omitempty"`
CloudInitDNSDomain *string `json:"searchdomain,omitempty"`
CloudInitDNSServer *string `json:"nameserver,omitempty"`
CloudInitFiles *CustomCloudInitFiles `json:"cicustom,omitempty"`
CloudInitPassword *string `json:"cipassword,omitempty"`
CloudInitSSHKeys *CustomCloudInitSSHKeys `json:"sshkeys,omitempty"`
CloudInitType *string `json:"citype,omitempty"`
CloudInitUsername *string `json:"ciuser,omitempty"`
CPUArchitecture *string `json:"arch,omitempty"`
CPUCores *int `json:"cores,omitempty"`
CPUEmulation *CustomCPUEmulation `json:"cpu,omitempty"`
CPULimit *int `json:"cpulimit,omitempty"`
CPUSockets *int `json:"sockets,omitempty"`
CPUUnits *int `json:"cpuunits,omitempty"`
DedicatedMemory *int `json:"memory,omitempty"`
DeletionProtection *types.CustomBool `json:"protection,omitempty"`
Description *string `json:"description,omitempty"`
EFIDisk *CustomEFIDisk `json:"efidisk0,omitempty"`
FloatingMemory *int `json:"balloon,omitempty"`
FloatingMemoryShares *int `json:"shares,omitempty"`
Freeze *types.CustomBool `json:"freeze,omitempty"`
HookScript *string `json:"hookscript,omitempty"`
Hotplug *types.CustomCommaSeparatedList `json:"hotplug,omitempty"`
Hugepages *string `json:"hugepages,omitempty"`
IDEDevice0 *CustomStorageDevice `json:"ide0,omitempty"`
IDEDevice1 *CustomStorageDevice `json:"ide1,omitempty"`
IDEDevice2 *CustomStorageDevice `json:"ide2,omitempty"`
IDEDevice3 *CustomStorageDevice `json:"ide3,omitempty"`
IPConfig0 *CustomCloudInitIPConfig `json:"ipconfig0,omitempty"`
IPConfig1 *CustomCloudInitIPConfig `json:"ipconfig1,omitempty"`
IPConfig2 *CustomCloudInitIPConfig `json:"ipconfig2,omitempty"`
IPConfig3 *CustomCloudInitIPConfig `json:"ipconfig3,omitempty"`
IPConfig4 *CustomCloudInitIPConfig `json:"ipconfig4,omitempty"`
IPConfig5 *CustomCloudInitIPConfig `json:"ipconfig5,omitempty"`
IPConfig6 *CustomCloudInitIPConfig `json:"ipconfig6,omitempty"`
IPConfig7 *CustomCloudInitIPConfig `json:"ipconfig7,omitempty"`
KeyboardLayout *string `json:"keyboard,omitempty"`
KVMArguments *string `json:"args,omitempty"`
KVMEnabled *types.CustomBool `json:"kvm,omitempty"`
LocalTime *types.CustomBool `json:"localtime,omitempty"`
Lock *string `json:"lock,omitempty"`
Machine *string `json:"machine,omitempty"`
MigrateDowntime *float64 `json:"migrate_downtime,omitempty"`
MigrateSpeed *int `json:"migrate_speed,omitempty"`
Name *string `json:"name,omitempty"`
NetworkDevice0 *CustomNetworkDevice `json:"net0,omitempty"`
NetworkDevice1 *CustomNetworkDevice `json:"net1,omitempty"`
NetworkDevice2 *CustomNetworkDevice `json:"net2,omitempty"`
NetworkDevice3 *CustomNetworkDevice `json:"net3,omitempty"`
NetworkDevice4 *CustomNetworkDevice `json:"net4,omitempty"`
NetworkDevice5 *CustomNetworkDevice `json:"net5,omitempty"`
NetworkDevice6 *CustomNetworkDevice `json:"net6,omitempty"`
NetworkDevice7 *CustomNetworkDevice `json:"net7,omitempty"`
NUMADevices *CustomNUMADevices `json:"numa_devices,omitempty"`
NUMAEnabled *types.CustomBool `json:"numa,omitempty"`
OSType *string `json:"ostype,omitempty"`
Overwrite *types.CustomBool `json:"force,omitempty"`
PCIDevice0 *CustomPCIDevice `json:"hostpci0,omitempty"`
PCIDevice1 *CustomPCIDevice `json:"hostpci1,omitempty"`
PCIDevice2 *CustomPCIDevice `json:"hostpci2,omitempty"`
PCIDevice3 *CustomPCIDevice `json:"hostpci3,omitempty"`
PoolID *string `json:"pool,omitempty" url:"pool,omitempty"`
Revert *string `json:"revert,omitempty"`
SATADevice0 *CustomStorageDevice `json:"sata0,omitempty"`
SATADevice1 *CustomStorageDevice `json:"sata1,omitempty"`
SATADevice2 *CustomStorageDevice `json:"sata2,omitempty"`
SATADevice3 *CustomStorageDevice `json:"sata3,omitempty"`
SATADevice4 *CustomStorageDevice `json:"sata4,omitempty"`
SATADevice5 *CustomStorageDevice `json:"sata5,omitempty"`
SCSIDevice0 *CustomStorageDevice `json:"scsi0,omitempty"`
SCSIDevice1 *CustomStorageDevice `json:"scsi1,omitempty"`
SCSIDevice2 *CustomStorageDevice `json:"scsi2,omitempty"`
SCSIDevice3 *CustomStorageDevice `json:"scsi3,omitempty"`
SCSIDevice4 *CustomStorageDevice `json:"scsi4,omitempty"`
SCSIDevice5 *CustomStorageDevice `json:"scsi5,omitempty"`
SCSIDevice6 *CustomStorageDevice `json:"scsi6,omitempty"`
SCSIDevice7 *CustomStorageDevice `json:"scsi7,omitempty"`
SCSIDevice8 *CustomStorageDevice `json:"scsi8,omitempty"`
SCSIDevice9 *CustomStorageDevice `json:"scsi9,omitempty"`
SCSIDevice10 *CustomStorageDevice `json:"scsi10,omitempty"`
SCSIDevice11 *CustomStorageDevice `json:"scsi11,omitempty"`
SCSIDevice12 *CustomStorageDevice `json:"scsi12,omitempty"`
SCSIDevice13 *CustomStorageDevice `json:"scsi13,omitempty"`
SCSIHardware *string `json:"scsihw,omitempty"`
SerialDevice0 *string `json:"serial0,omitempty"`
SerialDevice1 *string `json:"serial1,omitempty"`
SerialDevice2 *string `json:"serial2,omitempty"`
SerialDevice3 *string `json:"serial3,omitempty"`
SharedMemory *CustomSharedMemory `json:"ivshmem,omitempty"`
SkipLock *types.CustomBool `json:"skiplock,omitempty"`
SMBIOS *CustomSMBIOS `json:"smbios1,omitempty"`
SpiceEnhancements *CustomSpiceEnhancements `json:"spice_enhancements,omitempty"`
StartDate *string `json:"startdate,omitempty"`
StartOnBoot *types.CustomBool `json:"onboot,omitempty"`
StartupOrder *CustomStartupOrder `json:"startup,omitempty"`
TabletDeviceEnabled *types.CustomBool `json:"tablet,omitempty"`
Tags *string `json:"tags,omitempty"`
Template *types.CustomBool `json:"template,omitempty"`
TimeDriftFixEnabled *types.CustomBool `json:"tdf,omitempty"`
USBDevices *CustomUSBDevices `json:"usb,omitempty"`
VGADevice *CustomVGADevice `json:"vga,omitempty"`
VirtualCPUCount *int `json:"vcpus,omitempty"`
VirtualIODevice0 *CustomStorageDevice `json:"virtio0,omitempty"`
VirtualIODevice1 *CustomStorageDevice `json:"virtio1,omitempty"`
VirtualIODevice2 *CustomStorageDevice `json:"virtio2,omitempty"`
VirtualIODevice3 *CustomStorageDevice `json:"virtio3,omitempty"`
VirtualIODevice4 *CustomStorageDevice `json:"virtio4,omitempty"`
VirtualIODevice5 *CustomStorageDevice `json:"virtio5,omitempty"`
VirtualIODevice6 *CustomStorageDevice `json:"virtio6,omitempty"`
VirtualIODevice7 *CustomStorageDevice `json:"virtio7,omitempty"`
VirtualIODevice8 *CustomStorageDevice `json:"virtio8,omitempty"`
VirtualIODevice9 *CustomStorageDevice `json:"virtio9,omitempty"`
VirtualIODevice10 *CustomStorageDevice `json:"virtio10,omitempty"`
VirtualIODevice11 *CustomStorageDevice `json:"virtio11,omitempty"`
VirtualIODevice12 *CustomStorageDevice `json:"virtio12,omitempty"`
VirtualIODevice13 *CustomStorageDevice `json:"virtio13,omitempty"`
VirtualIODevice14 *CustomStorageDevice `json:"virtio14,omitempty"`
VirtualIODevice15 *CustomStorageDevice `json:"virtio15,omitempty"`
VMGenerationID *string `json:"vmgenid,omitempty"`
VMStateDatastoreID *string `json:"vmstatestorage,omitempty"`
WatchdogDevice *CustomWatchdogDevice `json:"watchdog,omitempty"`
ACPI *types2.CustomBool `json:"acpi,omitempty"`
Agent *CustomAgent `json:"agent,omitempty"`
AllowReboot *types2.CustomBool `json:"reboot,omitempty"`
AudioDevice *CustomAudioDevice `json:"audio0,omitempty"`
Autostart *types2.CustomBool `json:"autostart,omitempty"`
BackupFile *string `json:"archive,omitempty"`
BandwidthLimit *int `json:"bwlimit,omitempty"`
BIOS *string `json:"bios,omitempty"`
BootDisk *string `json:"bootdisk,omitempty"`
BootOrder *string `json:"boot,omitempty"`
CDROM *string `json:"cdrom,omitempty"`
CloudInitDNSDomain *string `json:"searchdomain,omitempty"`
CloudInitDNSServer *string `json:"nameserver,omitempty"`
CloudInitFiles *CustomCloudInitFiles `json:"cicustom,omitempty"`
CloudInitPassword *string `json:"cipassword,omitempty"`
CloudInitSSHKeys *CustomCloudInitSSHKeys `json:"sshkeys,omitempty"`
CloudInitType *string `json:"citype,omitempty"`
CloudInitUsername *string `json:"ciuser,omitempty"`
CPUArchitecture *string `json:"arch,omitempty"`
CPUCores *int `json:"cores,omitempty"`
CPUEmulation *CustomCPUEmulation `json:"cpu,omitempty"`
CPULimit *int `json:"cpulimit,omitempty"`
CPUSockets *int `json:"sockets,omitempty"`
CPUUnits *int `json:"cpuunits,omitempty"`
DedicatedMemory *int `json:"memory,omitempty"`
DeletionProtection *types2.CustomBool `json:"protection,omitempty"`
Description *string `json:"description,omitempty"`
EFIDisk *CustomEFIDisk `json:"efidisk0,omitempty"`
FloatingMemory *int `json:"balloon,omitempty"`
FloatingMemoryShares *int `json:"shares,omitempty"`
Freeze *types2.CustomBool `json:"freeze,omitempty"`
HookScript *string `json:"hookscript,omitempty"`
Hotplug *types2.CustomCommaSeparatedList `json:"hotplug,omitempty"`
Hugepages *string `json:"hugepages,omitempty"`
IDEDevice0 *CustomStorageDevice `json:"ide0,omitempty"`
IDEDevice1 *CustomStorageDevice `json:"ide1,omitempty"`
IDEDevice2 *CustomStorageDevice `json:"ide2,omitempty"`
IDEDevice3 *CustomStorageDevice `json:"ide3,omitempty"`
IPConfig0 *CustomCloudInitIPConfig `json:"ipconfig0,omitempty"`
IPConfig1 *CustomCloudInitIPConfig `json:"ipconfig1,omitempty"`
IPConfig2 *CustomCloudInitIPConfig `json:"ipconfig2,omitempty"`
IPConfig3 *CustomCloudInitIPConfig `json:"ipconfig3,omitempty"`
IPConfig4 *CustomCloudInitIPConfig `json:"ipconfig4,omitempty"`
IPConfig5 *CustomCloudInitIPConfig `json:"ipconfig5,omitempty"`
IPConfig6 *CustomCloudInitIPConfig `json:"ipconfig6,omitempty"`
IPConfig7 *CustomCloudInitIPConfig `json:"ipconfig7,omitempty"`
KeyboardLayout *string `json:"keyboard,omitempty"`
KVMArguments *string `json:"args,omitempty"`
KVMEnabled *types2.CustomBool `json:"kvm,omitempty"`
LocalTime *types2.CustomBool `json:"localtime,omitempty"`
Lock *string `json:"lock,omitempty"`
Machine *string `json:"machine,omitempty"`
MigrateDowntime *float64 `json:"migrate_downtime,omitempty"`
MigrateSpeed *int `json:"migrate_speed,omitempty"`
Name *string `json:"name,omitempty"`
NetworkDevice0 *CustomNetworkDevice `json:"net0,omitempty"`
NetworkDevice1 *CustomNetworkDevice `json:"net1,omitempty"`
NetworkDevice2 *CustomNetworkDevice `json:"net2,omitempty"`
NetworkDevice3 *CustomNetworkDevice `json:"net3,omitempty"`
NetworkDevice4 *CustomNetworkDevice `json:"net4,omitempty"`
NetworkDevice5 *CustomNetworkDevice `json:"net5,omitempty"`
NetworkDevice6 *CustomNetworkDevice `json:"net6,omitempty"`
NetworkDevice7 *CustomNetworkDevice `json:"net7,omitempty"`
NUMADevices *CustomNUMADevices `json:"numa_devices,omitempty"`
NUMAEnabled *types2.CustomBool `json:"numa,omitempty"`
OSType *string `json:"ostype,omitempty"`
Overwrite *types2.CustomBool `json:"force,omitempty"`
PCIDevice0 *CustomPCIDevice `json:"hostpci0,omitempty"`
PCIDevice1 *CustomPCIDevice `json:"hostpci1,omitempty"`
PCIDevice2 *CustomPCIDevice `json:"hostpci2,omitempty"`
PCIDevice3 *CustomPCIDevice `json:"hostpci3,omitempty"`
PoolID *string `json:"pool,omitempty" url:"pool,omitempty"`
Revert *string `json:"revert,omitempty"`
SATADevice0 *CustomStorageDevice `json:"sata0,omitempty"`
SATADevice1 *CustomStorageDevice `json:"sata1,omitempty"`
SATADevice2 *CustomStorageDevice `json:"sata2,omitempty"`
SATADevice3 *CustomStorageDevice `json:"sata3,omitempty"`
SATADevice4 *CustomStorageDevice `json:"sata4,omitempty"`
SATADevice5 *CustomStorageDevice `json:"sata5,omitempty"`
SCSIDevice0 *CustomStorageDevice `json:"scsi0,omitempty"`
SCSIDevice1 *CustomStorageDevice `json:"scsi1,omitempty"`
SCSIDevice2 *CustomStorageDevice `json:"scsi2,omitempty"`
SCSIDevice3 *CustomStorageDevice `json:"scsi3,omitempty"`
SCSIDevice4 *CustomStorageDevice `json:"scsi4,omitempty"`
SCSIDevice5 *CustomStorageDevice `json:"scsi5,omitempty"`
SCSIDevice6 *CustomStorageDevice `json:"scsi6,omitempty"`
SCSIDevice7 *CustomStorageDevice `json:"scsi7,omitempty"`
SCSIDevice8 *CustomStorageDevice `json:"scsi8,omitempty"`
SCSIDevice9 *CustomStorageDevice `json:"scsi9,omitempty"`
SCSIDevice10 *CustomStorageDevice `json:"scsi10,omitempty"`
SCSIDevice11 *CustomStorageDevice `json:"scsi11,omitempty"`
SCSIDevice12 *CustomStorageDevice `json:"scsi12,omitempty"`
SCSIDevice13 *CustomStorageDevice `json:"scsi13,omitempty"`
SCSIHardware *string `json:"scsihw,omitempty"`
SerialDevice0 *string `json:"serial0,omitempty"`
SerialDevice1 *string `json:"serial1,omitempty"`
SerialDevice2 *string `json:"serial2,omitempty"`
SerialDevice3 *string `json:"serial3,omitempty"`
SharedMemory *CustomSharedMemory `json:"ivshmem,omitempty"`
SkipLock *types2.CustomBool `json:"skiplock,omitempty"`
SMBIOS *CustomSMBIOS `json:"smbios1,omitempty"`
SpiceEnhancements *CustomSpiceEnhancements `json:"spice_enhancements,omitempty"`
StartDate *string `json:"startdate,omitempty"`
StartOnBoot *types2.CustomBool `json:"onboot,omitempty"`
StartupOrder *CustomStartupOrder `json:"startup,omitempty"`
TabletDeviceEnabled *types2.CustomBool `json:"tablet,omitempty"`
Tags *string `json:"tags,omitempty"`
Template *types2.CustomBool `json:"template,omitempty"`
TimeDriftFixEnabled *types2.CustomBool `json:"tdf,omitempty"`
USBDevices *CustomUSBDevices `json:"usb,omitempty"`
VGADevice *CustomVGADevice `json:"vga,omitempty"`
VirtualCPUCount *int `json:"vcpus,omitempty"`
VirtualIODevice0 *CustomStorageDevice `json:"virtio0,omitempty"`
VirtualIODevice1 *CustomStorageDevice `json:"virtio1,omitempty"`
VirtualIODevice2 *CustomStorageDevice `json:"virtio2,omitempty"`
VirtualIODevice3 *CustomStorageDevice `json:"virtio3,omitempty"`
VirtualIODevice4 *CustomStorageDevice `json:"virtio4,omitempty"`
VirtualIODevice5 *CustomStorageDevice `json:"virtio5,omitempty"`
VirtualIODevice6 *CustomStorageDevice `json:"virtio6,omitempty"`
VirtualIODevice7 *CustomStorageDevice `json:"virtio7,omitempty"`
VirtualIODevice8 *CustomStorageDevice `json:"virtio8,omitempty"`
VirtualIODevice9 *CustomStorageDevice `json:"virtio9,omitempty"`
VirtualIODevice10 *CustomStorageDevice `json:"virtio10,omitempty"`
VirtualIODevice11 *CustomStorageDevice `json:"virtio11,omitempty"`
VirtualIODevice12 *CustomStorageDevice `json:"virtio12,omitempty"`
VirtualIODevice13 *CustomStorageDevice `json:"virtio13,omitempty"`
VirtualIODevice14 *CustomStorageDevice `json:"virtio14,omitempty"`
VirtualIODevice15 *CustomStorageDevice `json:"virtio15,omitempty"`
VMGenerationID *string `json:"vmgenid,omitempty"`
VMStateDatastoreID *string `json:"vmstatestorage,omitempty"`
WatchdogDevice *CustomWatchdogDevice `json:"watchdog,omitempty"`
}
// GetStatusResponseBody contains the body from a VM get status response.
@ -495,19 +496,19 @@ type GetStatusResponseBody struct {
// GetStatusResponseData contains the data from a VM get status response.
type GetStatusResponseData struct {
AgentEnabled *types.CustomBool `json:"agent,omitempty"`
CPUCount *float64 `json:"cpus,omitempty"`
Lock *string `json:"lock,omitempty"`
MemoryAllocation *int `json:"maxmem,omitempty"`
Name *string `json:"name,omitempty"`
PID *int `json:"pid,omitempty"`
QMPStatus *string `json:"qmpstatus,omitempty"`
RootDiskSize *int `json:"maxdisk,omitempty"`
SpiceSupport *types.CustomBool `json:"spice,omitempty"`
Status string `json:"status,omitempty"`
Tags *string `json:"tags,omitempty"`
Uptime *int `json:"uptime,omitempty"`
VMID *int `json:"vmid,omitempty"`
AgentEnabled *types2.CustomBool `json:"agent,omitempty"`
CPUCount *float64 `json:"cpus,omitempty"`
Lock *string `json:"lock,omitempty"`
MemoryAllocation *int `json:"maxmem,omitempty"`
Name *string `json:"name,omitempty"`
PID *int `json:"pid,omitempty"`
QMPStatus *string `json:"qmpstatus,omitempty"`
RootDiskSize *int `json:"maxdisk,omitempty"`
SpiceSupport *types2.CustomBool `json:"spice,omitempty"`
Status string `json:"status,omitempty"`
Tags *string `json:"tags,omitempty"`
Uptime *int `json:"uptime,omitempty"`
VMID *int `json:"vmid,omitempty"`
}
// ListResponseBody contains the body from a virtual machine list response.
@ -524,10 +525,10 @@ type ListResponseData struct {
// MigrateRequestBody contains the body for a VM migration request.
type MigrateRequestBody struct {
OnlineMigration *types.CustomBool `json:"online,omitempty" url:"online,omitempty"`
TargetNode string `json:"target" url:"target"`
TargetStorage *string `json:"targetstorage,omitempty" url:"targetstorage,omitempty"`
WithLocalDisks *types.CustomBool `json:"with-local-disks,omitempty" url:"with-local-disks,omitempty,int"`
OnlineMigration *types2.CustomBool `json:"online,omitempty" url:"online,omitempty"`
TargetNode string `json:"target" url:"target"`
TargetStorage *string `json:"targetstorage,omitempty" url:"targetstorage,omitempty"`
WithLocalDisks *types2.CustomBool `json:"with-local-disks,omitempty" url:"with-local-disks,omitempty,int"`
}
// MigrateResponseBody contains the body from a VM migrate response.
@ -537,12 +538,12 @@ type MigrateResponseBody struct {
// MoveDiskRequestBody contains the body for a VM move disk request.
type MoveDiskRequestBody struct {
BandwidthLimit *int `json:"bwlimit,omitempty" url:"bwlimit,omitempty"`
DeleteOriginalDisk *types.CustomBool `json:"delete,omitempty" url:"delete,omitempty,int"`
Digest *string `json:"digest,omitempty" url:"digest,omitempty"`
Disk string `json:"disk" url:"disk"`
TargetStorage string `json:"storage" url:"storage"`
TargetStorageFormat *string `json:"format,omitempty" url:"format,omitempty"`
BandwidthLimit *int `json:"bwlimit,omitempty" url:"bwlimit,omitempty"`
DeleteOriginalDisk *types2.CustomBool `json:"delete,omitempty" url:"delete,omitempty,int"`
Digest *string `json:"digest,omitempty" url:"digest,omitempty"`
Disk string `json:"disk" url:"disk"`
TargetStorage string `json:"storage" url:"storage"`
TargetStorageFormat *string `json:"format,omitempty" url:"format,omitempty"`
}
// MoveDiskResponseBody contains the body from a VM move disk response.
@ -562,18 +563,18 @@ type RebootResponseBody struct {
// ResizeDiskRequestBody contains the body for a VM resize disk request.
type ResizeDiskRequestBody struct {
Digest *string `json:"digest,omitempty" url:"digest,omitempty"`
Disk string `json:"disk" url:"disk"`
Size types.DiskSize `json:"size" url:"size"`
SkipLock *types.CustomBool `json:"skiplock,omitempty" url:"skiplock,omitempty,int"`
Digest *string `json:"digest,omitempty" url:"digest,omitempty"`
Disk string `json:"disk" url:"disk"`
Size types.DiskSize `json:"size" url:"size"`
SkipLock *types2.CustomBool `json:"skiplock,omitempty" url:"skiplock,omitempty,int"`
}
// ShutdownRequestBody contains the body for a VM shutdown request.
type ShutdownRequestBody struct {
ForceStop *types.CustomBool `json:"forceStop,omitempty" url:"forceStop,omitempty,int"`
KeepActive *types.CustomBool `json:"keepActive,omitempty" url:"keepActive,omitempty,int"`
SkipLock *types.CustomBool `json:"skipLock,omitempty" url:"skipLock,omitempty,int"`
Timeout *int `json:"timeout,omitempty" url:"timeout,omitempty"`
ForceStop *types2.CustomBool `json:"forceStop,omitempty" url:"forceStop,omitempty,int"`
KeepActive *types2.CustomBool `json:"keepActive,omitempty" url:"keepActive,omitempty,int"`
SkipLock *types2.CustomBool `json:"skipLock,omitempty" url:"skipLock,omitempty,int"`
Timeout *int `json:"timeout,omitempty" url:"timeout,omitempty"`
}
// ShutdownResponseBody contains the body from a VM shutdown response.
@ -1267,15 +1268,15 @@ func (r *CustomAgent) UnmarshalJSON(b []byte) error {
v := strings.Split(strings.TrimSpace(p), "=")
if len(v) == 1 {
enabled := types.CustomBool(v[0] == "1")
enabled := types2.CustomBool(v[0] == "1")
r.Enabled = &enabled
} else if len(v) == 2 {
switch v[0] {
case "enabled":
enabled := types.CustomBool(v[1] == "1")
enabled := types2.CustomBool(v[1] == "1")
r.Enabled = &enabled
case "fstrim_cloned_disks":
fstrim := types.CustomBool(v[1] == "1")
fstrim := types2.CustomBool(v[1] == "1")
r.TrimClonedDisks = &fstrim
case "type":
r.Type = &v[1]
@ -1450,7 +1451,7 @@ func (r *CustomCPUEmulation) UnmarshalJSON(b []byte) error {
r.Flags = &f
}
case "hidden":
bv := types.CustomBool(v[1] == "1")
bv := types2.CustomBool(v[1] == "1")
r.Hidden = &bv
case "hv-vendor-id":
r.HVVendorID = &v[1]
@ -1513,10 +1514,10 @@ func (r *CustomNetworkDevice) UnmarshalJSON(b []byte) error {
case "bridge":
r.Bridge = &v[1]
case "firewall":
bv := types.CustomBool(v[1] == "1")
bv := types2.CustomBool(v[1] == "1")
r.Firewall = &bv
case "link_down":
bv := types.CustomBool(v[1] == "1")
bv := types2.CustomBool(v[1] == "1")
r.LinkDown = &bv
case "macaddr":
r.MACAddress = &v[1]
@ -1597,15 +1598,15 @@ func (r *CustomPCIDevice) UnmarshalJSON(b []byte) error {
case "mdev":
r.MDev = &v[1]
case "pcie":
bv := types.CustomBool(v[1] == "1")
bv := types2.CustomBool(v[1] == "1")
r.PCIExpress = &bv
case "rombar":
bv := types.CustomBool(v[1] == "1")
bv := types2.CustomBool(v[1] == "1")
r.ROMBAR = &bv
case "romfile":
r.ROMFile = &v[1]
case "x-vga":
bv := types.CustomBool(v[1] == "1")
bv := types2.CustomBool(v[1] == "1")
r.XVGA = &bv
}
}
@ -1661,7 +1662,7 @@ func (r *CustomSMBIOS) UnmarshalJSON(b []byte) error {
if len(v) == 2 {
switch v[0] {
case "base64":
base64 := types.CustomBool(v[1] == "1")
base64 := types2.CustomBool(v[1] == "1")
r.Base64 = &base64
case "family":
r.Family = &v[1]
@ -1711,7 +1712,7 @@ func (r *CustomStorageDevice) UnmarshalJSON(b []byte) error {
case "aio":
r.AIO = &v[1]
case "backup":
bv := types.CustomBool(v[1] == "1")
bv := types2.CustomBool(v[1] == "1")
r.BackupEnabled = &bv
case "file":
r.FileVolume = v[1]
@ -1754,10 +1755,10 @@ func (r *CustomStorageDevice) UnmarshalJSON(b []byte) error {
case "format":
r.Format = &v[1]
case "iothread":
bv := types.CustomBool(v[1] == "1")
bv := types2.CustomBool(v[1] == "1")
r.IOThread = &bv
case "ssd":
bv := types.CustomBool(v[1] == "1")
bv := types2.CustomBool(v[1] == "1")
r.SSD = &bv
case "discard":
r.Discard = &v[1]

View File

@ -7,7 +7,7 @@
package storage
import (
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
"github.com/bpg/terraform-provider-proxmox/internal/types"
)
// DatastoreGetResponseBody contains the body from a datastore get response.

View File

@ -6,13 +6,15 @@
package types
import "github.com/bpg/terraform-provider-proxmox/internal/types"
// StrPtr returns a pointer to a string.
func StrPtr(s string) *string {
return &s
}
// BoolPtr returns a pointer to a bool.
func BoolPtr(s bool) *CustomBool {
customBool := CustomBool(s)
func BoolPtr(s bool) *types.CustomBool {
customBool := types.CustomBool(s)
return &customBool
}

View File

@ -30,7 +30,7 @@ func ProxmoxVirtualEnvironment() *schema.Provider {
}
}
func providerConfigure(ctx context.Context, d *schema.ResourceData) (interface{}, diag.Diagnostics) {
func providerConfigure(_ context.Context, d *schema.ResourceData) (interface{}, diag.Diagnostics) {
var err error
var diags diag.Diagnostics
@ -43,44 +43,25 @@ func providerConfigure(ctx context.Context, d *schema.ResourceData) (interface{}
var conn *api.Connection
// Legacy configuration, wrapped in the deprecated `virtual_environment` block
veConfigBlock := d.Get(mkProviderVirtualEnvironment).([]interface{})
if len(veConfigBlock) > 0 {
veConfig := veConfigBlock[0].(map[string]interface{})
creds, err = api.NewCredentials(
veConfig[mkProviderUsername].(string),
veConfig[mkProviderPassword].(string),
veConfig[mkProviderOTP].(string),
"",
)
diags = append(diags, diag.FromErr(err)...)
creds, err = api.NewCredentials(
d.Get(mkProviderUsername).(string),
d.Get(mkProviderPassword).(string),
d.Get(mkProviderOTP).(string),
d.Get(mkProviderAPIToken).(string),
)
diags = append(diags, diag.FromErr(err)...)
conn, err = api.NewConnection(
veConfig[mkProviderEndpoint].(string),
veConfig[mkProviderInsecure].(bool),
)
diags = append(diags, diag.FromErr(err)...)
} else {
creds, err = api.NewCredentials(
d.Get(mkProviderUsername).(string),
d.Get(mkProviderPassword).(string),
d.Get(mkProviderOTP).(string),
d.Get(mkProviderAPIToken).(string),
)
diags = append(diags, diag.FromErr(err)...)
conn, err = api.NewConnection(
d.Get(mkProviderEndpoint).(string),
d.Get(mkProviderInsecure).(bool),
)
diags = append(diags, diag.FromErr(err)...)
}
conn, err = api.NewConnection(
d.Get(mkProviderEndpoint).(string),
d.Get(mkProviderInsecure).(bool),
)
diags = append(diags, diag.FromErr(err)...)
if diags.HasError() {
return nil, diags
}
apiClient, err = api.NewClient(ctx, creds, conn)
apiClient, err = api.NewClient(creds, conn)
if err != nil {
return nil, diag.Errorf("error creating virtual environment client: %s", err)
}
@ -145,12 +126,27 @@ type apiResolver struct {
func (r *apiResolver) Resolve(ctx context.Context, nodeName string) (string, error) {
nc := &nodes.Client{Client: r.c, NodeName: nodeName}
ip, err := nc.GetIP(ctx)
networkDevices, err := nc.ListNetworkInterfaces(ctx)
if err != nil {
return "", fmt.Errorf("failed to get node IP: %w", err)
return "", fmt.Errorf("failed to list network devices of node \"%s\": %w", nc.NodeName, err)
}
return ip, nil
nodeAddress := ""
for _, d := range networkDevices {
if d.Address != nil {
nodeAddress = *d.Address
break
}
}
if nodeAddress == "" {
return "", fmt.Errorf("failed to determine the IP address of node \"%s\"", nc.NodeName)
}
nodeAddressParts := strings.Split(nodeAddress, "/")
return nodeAddressParts[0], nil
}
type apiResolverWithOverrides struct {

View File

@ -33,7 +33,6 @@ func TestProviderSchema(t *testing.T) {
}
test.AssertOptionalArguments(t, s, []string{
mkProviderVirtualEnvironment,
mkProviderUsername,
mkProviderPassword,
mkProviderEndpoint,
@ -42,32 +41,11 @@ func TestProviderSchema(t *testing.T) {
})
test.AssertValueTypes(t, s, map[string]schema.ValueType{
mkProviderVirtualEnvironment: schema.TypeList,
mkProviderUsername: schema.TypeString,
mkProviderPassword: schema.TypeString,
mkProviderEndpoint: schema.TypeString,
mkProviderInsecure: schema.TypeBool,
mkProviderOTP: schema.TypeString,
})
veSchema := test.AssertNestedSchemaExistence(t, s, mkProviderVirtualEnvironment)
test.AssertOptionalArguments(t, veSchema, []string{
mkProviderEndpoint,
mkProviderInsecure,
mkProviderOTP,
mkProviderPassword,
mkProviderUsername,
mkProviderSSH,
})
test.AssertValueTypes(t, veSchema, map[string]schema.ValueType{
mkProviderUsername: schema.TypeString,
mkProviderPassword: schema.TypeString,
mkProviderEndpoint: schema.TypeString,
mkProviderInsecure: schema.TypeBool,
mkProviderOTP: schema.TypeString,
mkProviderPassword: schema.TypeString,
mkProviderUsername: schema.TypeString,
mkProviderSSH: schema.TypeList,
})
providerSSHSchema := test.AssertNestedSchemaExistence(t, s, mkProviderSSH)

View File

@ -17,21 +17,22 @@ import (
func createResourceMap() map[string]*schema.Resource {
return map[string]*schema.Resource{
"proxmox_virtual_environment_certificate": resource.Certificate(),
"proxmox_virtual_environment_firewall_alias": firewall.Alias(),
"proxmox_virtual_environment_firewall_ipset": firewall.IPSet(),
"proxmox_virtual_environment_firewall_rules": firewall.Rules(),
"proxmox_virtual_environment_firewall_options": firewall.Options(),
"proxmox_virtual_environment_cluster_firewall_security_group": clusterfirewall.SecurityGroup(),
"proxmox_virtual_environment_cluster_firewall": clusterfirewall.Firewall(),
"proxmox_virtual_environment_cluster_firewall_security_group": clusterfirewall.SecurityGroup(),
"proxmox_virtual_environment_container": resource.Container(),
"proxmox_virtual_environment_dns": resource.DNS(),
"proxmox_virtual_environment_file": resource.File(),
"proxmox_virtual_environment_firewall_alias": firewall.Alias(),
"proxmox_virtual_environment_firewall_ipset": firewall.IPSet(),
"proxmox_virtual_environment_firewall_options": firewall.Options(),
"proxmox_virtual_environment_firewall_rules": firewall.Rules(),
"proxmox_virtual_environment_group": resource.Group(),
"proxmox_virtual_environment_hosts": resource.Hosts(),
"proxmox_virtual_environment_pool": resource.Pool(),
"proxmox_virtual_environment_role": resource.Role(),
"proxmox_virtual_environment_time": resource.Time(),
"proxmox_virtual_environment_user": resource.User(),
"proxmox_virtual_environment_vm": resource.VM(),
// "proxmox_virtual_environment_network_linux_bridge": resource.NetworkLinuxBridge(),
"proxmox_virtual_environment_pool": resource.Pool(),
"proxmox_virtual_environment_role": resource.Role(),
"proxmox_virtual_environment_time": resource.Time(),
"proxmox_virtual_environment_user": resource.User(),
"proxmox_virtual_environment_vm": resource.VM(),
}
}

View File

@ -7,7 +7,6 @@
package provider
import (
"fmt"
"os"
"regexp"
@ -16,19 +15,18 @@ import (
)
const (
dvProviderOTP = ""
mkProviderVirtualEnvironment = "virtual_environment"
mkProviderEndpoint = "endpoint"
mkProviderInsecure = "insecure"
mkProviderOTP = "otp"
mkProviderPassword = "password"
mkProviderUsername = "username"
mkProviderAPIToken = "api_token"
mkProviderSSH = "ssh"
mkProviderSSHUsername = "username"
mkProviderSSHPassword = "password"
mkProviderSSHAgent = "agent"
mkProviderSSHAgentSocket = "agent_socket"
dvProviderOTP = ""
mkProviderEndpoint = "endpoint"
mkProviderInsecure = "insecure"
mkProviderOTP = "otp"
mkProviderPassword = "password"
mkProviderUsername = "username"
mkProviderAPIToken = "api_token"
mkProviderSSH = "ssh"
mkProviderSSHUsername = "username"
mkProviderSSHPassword = "password"
mkProviderSSHAgent = "agent"
mkProviderSSHAgentSocket = "agent_socket"
mkProviderSSHNode = "node"
mkProviderSSHNodeName = "name"
@ -36,40 +34,21 @@ const (
)
func createSchema() map[string]*schema.Schema {
providerSchema := nestedProviderSchema()
providerSchema[mkProviderVirtualEnvironment] = &schema.Schema{
Type: schema.TypeList,
Optional: true,
Elem: &schema.Resource{
Schema: nestedProviderSchema(),
},
MaxItems: 1,
Deprecated: "Move attributes out of virtual_environment block",
}
return providerSchema
}
func nestedProviderSchema() map[string]*schema.Schema {
return map[string]*schema.Schema{
mkProviderEndpoint: {
Type: schema.TypeString,
Optional: true,
Description: "The endpoint for the Proxmox Virtual Environment API",
Description: "The endpoint for the Proxmox VE API.",
DefaultFunc: schema.MultiEnvDefaultFunc(
[]string{"PROXMOX_VE_ENDPOINT", "PM_VE_ENDPOINT"},
nil,
),
AtLeastOneOf: []string{
mkProviderEndpoint,
fmt.Sprintf("%s.0.%s", mkProviderVirtualEnvironment, mkProviderEndpoint),
},
ValidateFunc: validation.IsURLWithHTTPorHTTPS,
},
mkProviderInsecure: {
Type: schema.TypeBool,
Optional: true,
Description: "Whether to skip the TLS verification step",
Description: "Whether to skip the TLS verification step.",
DefaultFunc: func() (interface{}, error) {
for _, k := range []string{"PROXMOX_VE_INSECURE", "PM_VE_INSECURE"} {
v := os.Getenv(k)
@ -85,24 +64,25 @@ func nestedProviderSchema() map[string]*schema.Schema {
mkProviderOTP: {
Type: schema.TypeString,
Optional: true,
Description: "The one-time password for the Proxmox Virtual Environment API",
Description: "The one-time password for the Proxmox VE API.",
Deprecated: "The `otp` attribute is deprecated and will be removed in a future release. " +
"Please use the `api_token` attribute instead.",
DefaultFunc: schema.MultiEnvDefaultFunc(
[]string{"PROXMOX_VE_OTP", "PM_VE_OTP"},
dvProviderOTP,
nil,
),
},
mkProviderPassword: {
Type: schema.TypeString,
Optional: true,
Sensitive: true,
Description: "The password for the Proxmox Virtual Environment API",
Description: "The password for the Proxmox VE API.",
DefaultFunc: schema.MultiEnvDefaultFunc(
[]string{"PROXMOX_VE_PASSWORD", "PM_VE_PASSWORD"},
nil,
),
AtLeastOneOf: []string{
mkProviderPassword,
fmt.Sprintf("%s.0.%s", mkProviderVirtualEnvironment, mkProviderPassword),
mkProviderAPIToken,
},
ValidateFunc: validation.StringIsNotEmpty,
@ -110,14 +90,13 @@ func nestedProviderSchema() map[string]*schema.Schema {
mkProviderUsername: {
Type: schema.TypeString,
Optional: true,
Description: "The username for the Proxmox Virtual Environment API",
Description: "The username for the Proxmox VE API.",
DefaultFunc: schema.MultiEnvDefaultFunc(
[]string{"PROXMOX_VE_USERNAME", "PM_VE_USERNAME"},
nil,
),
AtLeastOneOf: []string{
mkProviderUsername,
fmt.Sprintf("%s.0.%s", mkProviderVirtualEnvironment, mkProviderUsername),
mkProviderAPIToken,
},
ValidateFunc: validation.StringIsNotEmpty,
@ -126,7 +105,7 @@ func nestedProviderSchema() map[string]*schema.Schema {
Type: schema.TypeString,
Optional: true,
Sensitive: true,
Description: "The API token for the Proxmox Virtual Environment API",
Description: "The API token for the Proxmox VE API.",
DefaultFunc: schema.MultiEnvDefaultFunc(
[]string{"PROXMOX_VE_API_TOKEN", "PM_VE_API_TOKEN"},
nil,
@ -140,14 +119,15 @@ func nestedProviderSchema() map[string]*schema.Schema {
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Description: "The SSH connection configuration to a Proxmox node",
Description: "The SSH configuration for the Proxmox nodes.",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
mkProviderSSHUsername: {
Type: schema.TypeString,
Optional: true,
Description: fmt.Sprintf("The username used for the SSH connection, "+
"defaults to the user specified in '%s'", mkProviderUsername),
Description: "The username used for the SSH connection. " +
"Defaults to the value of the `username` field of the " +
"`provider` block.",
DefaultFunc: schema.MultiEnvDefaultFunc(
[]string{"PROXMOX_VE_SSH_USERNAME", "PM_VE_SSH_USERNAME"},
nil,
@ -158,8 +138,9 @@ func nestedProviderSchema() map[string]*schema.Schema {
Type: schema.TypeString,
Optional: true,
Sensitive: true,
Description: fmt.Sprintf("The password used for the SSH connection, "+
"defaults to the password specified in '%s'", mkProviderPassword),
Description: "The password used for the SSH connection. " +
"Defaults to the value of the `password` field of the " +
"`provider` block.",
DefaultFunc: schema.MultiEnvDefaultFunc(
[]string{"PROXMOX_VE_SSH_PASSWORD", "PM_VE_SSH_PASSWORD"},
nil,
@ -167,9 +148,10 @@ func nestedProviderSchema() map[string]*schema.Schema {
ValidateFunc: validation.StringIsNotEmpty,
},
mkProviderSSHAgent: {
Type: schema.TypeBool,
Optional: true,
Description: "Whether to use the SSH agent for the SSH authentication. Defaults to false",
Type: schema.TypeBool,
Optional: true,
Description: "Whether to use the SSH agent for authentication. " +
"Defaults to `false`.",
DefaultFunc: func() (interface{}, error) {
for _, k := range []string{"PROXMOX_VE_SSH_AGENT", "PM_VE_SSH_AGENT"} {
v := os.Getenv(k)
@ -186,7 +168,7 @@ func nestedProviderSchema() map[string]*schema.Schema {
Type: schema.TypeString,
Optional: true,
Description: "The path to the SSH agent socket. Defaults to the value of the `SSH_AUTH_SOCK` " +
"environment variable",
"environment variable.",
DefaultFunc: schema.MultiEnvDefaultFunc(
[]string{"SSH_AUTH_SOCK", "PROXMOX_VE_SSH_AUTH_SOCK", "PM_VE_SSH_AUTH_SOCK"},
nil,
@ -197,19 +179,19 @@ func nestedProviderSchema() map[string]*schema.Schema {
Type: schema.TypeList,
Optional: true,
MinItems: 0,
Description: "Overrides for SSH connection configuration to a Proxmox node",
Description: "Overrides for SSH connection configuration for a Proxmox VE node.",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
mkProviderSSHNodeName: {
Type: schema.TypeString,
Required: true,
Description: "The name of the node to connect to",
Description: "The name of the Proxmox VE node.",
ValidateFunc: validation.StringIsNotEmpty,
},
mkProviderSSHNodeAddress: {
Type: schema.TypeString,
Required: true,
Description: "The address that should be used to connect to the node",
Description: "The address of the Proxmox VE node.",
ValidateFunc: validation.IsIPAddress,
},
},

View File

@ -15,8 +15,8 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/bpg/terraform-provider-proxmox/internal/types"
"github.com/bpg/terraform-provider-proxmox/proxmox/nodes"
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
"github.com/bpg/terraform-provider-proxmox/proxmoxtf"
)

View File

@ -12,8 +12,8 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/bpg/terraform-provider-proxmox/internal/types"
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster/firewall"
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
"github.com/bpg/terraform-provider-proxmox/proxmoxtf"
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/resource/validator"
)

View File

@ -17,8 +17,8 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/bpg/terraform-provider-proxmox/internal/types"
"github.com/bpg/terraform-provider-proxmox/proxmox/nodes/containers"
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
"github.com/bpg/terraform-provider-proxmox/proxmoxtf"
)

View File

@ -13,8 +13,8 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/bpg/terraform-provider-proxmox/internal/types"
"github.com/bpg/terraform-provider-proxmox/proxmox/firewall"
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/structure"
)

View File

@ -12,8 +12,8 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/bpg/terraform-provider-proxmox/internal/types"
"github.com/bpg/terraform-provider-proxmox/proxmox/firewall"
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/resource/validator"
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/structure"
)

View File

@ -15,8 +15,8 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/bpg/terraform-provider-proxmox/internal/types"
"github.com/bpg/terraform-provider-proxmox/proxmox/firewall"
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/resource/validator"
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/structure"
)

View File

@ -13,8 +13,8 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/bpg/terraform-provider-proxmox/internal/types"
"github.com/bpg/terraform-provider-proxmox/proxmox/access"
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
"github.com/bpg/terraform-provider-proxmox/proxmoxtf"
)

View File

@ -13,8 +13,8 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/bpg/terraform-provider-proxmox/internal/types"
"github.com/bpg/terraform-provider-proxmox/proxmox/access"
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
"github.com/bpg/terraform-provider-proxmox/proxmoxtf"
)

View File

@ -15,8 +15,8 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/bpg/terraform-provider-proxmox/internal/types"
"github.com/bpg/terraform-provider-proxmox/proxmox/access"
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
"github.com/bpg/terraform-provider-proxmox/proxmoxtf"
)

View File

@ -352,39 +352,6 @@ func getSCSIHardwareValidator() schema.SchemaValidateDiagFunc {
}, false))
}
//nolint:unused
func getVLANIDsValidator() schema.SchemaValidateDiagFunc {
return validation.ToDiagFunc(func(i interface{}, k string) (ws []string, es []error) {
min := 1
max := 4094
list, ok := i.([]interface{})
if !ok {
es = append(es, fmt.Errorf("expected type of %s to be []interface{}", k))
return
}
for li, lv := range list {
v, ok := lv.(int)
if !ok {
es = append(es, fmt.Errorf("expected type of %s[%d] to be int", k, li))
return
}
if v != -1 {
if v < min || v > max {
es = append(es, fmt.Errorf("expected %s[%d] to be in the range (%d - %d), got %d", k, li, min, max, v))
return
}
}
}
return
})
}
func getVMIDValidator() schema.SchemaValidateDiagFunc {
return validation.ToDiagFunc(func(i interface{}, k string) (ws []string, es []error) {
min := 100

View File

@ -0,0 +1,76 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package validator
import (
"fmt"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)
// VLANIDsValidator returns a schema validation function for VLAN IDs.
func VLANIDsValidator() schema.SchemaValidateDiagFunc {
return validation.ToDiagFunc(func(i interface{}, k string) ([]string, []error) {
min := 1
max := 4094
var ws []string
var es []error
list, ok := i.([]interface{})
if !ok {
es = append(es, fmt.Errorf("expected type of %s to be []interface{}", k))
return ws, es
}
for li, lv := range list {
v, ok := lv.(int)
if !ok {
es = append(es, fmt.Errorf("expected type of %s[%d] to be int", k, li))
return ws, es
}
if v != -1 {
if v < min || v > max {
es = append(es, fmt.Errorf("expected %s[%d] to be in the range (%d - %d), got %d", k, li, min, max, v))
return ws, es
}
}
}
return ws, es
})
}
// NodeNetworkInterfaceBondingModes returns a schema validation function for a node network interface bonding mode.
func NodeNetworkInterfaceBondingModes() schema.SchemaValidateDiagFunc {
return validation.ToDiagFunc(validation.StringInSlice([]string{
"balance-rr",
"active-backup",
"balance-xor",
"broadcast",
"802.3ad",
"balance-tlb",
"balance-alb",
"balance-slb",
"lacp-balance-slb",
"lacp-balance-tcp",
}, false))
}
// NodeNetworkInterfaceBondingTransmitHashPolicies returns a schema validation function for a node network interface
// bonding transmit hash policy.
func NodeNetworkInterfaceBondingTransmitHashPolicies() schema.SchemaValidateDiagFunc {
return validation.ToDiagFunc(validation.StringInSlice([]string{
"layer2",
"layer2+3",
"layer3+4",
}, false))
}

View File

@ -20,6 +20,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
types2 "github.com/bpg/terraform-provider-proxmox/internal/types"
"github.com/bpg/terraform-provider-proxmox/proxmox/nodes/vms"
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
"github.com/bpg/terraform-provider-proxmox/proxmoxtf"
@ -1311,7 +1312,7 @@ func vmCreateClone(ctx context.Context, d *schema.ResourceData, m interface{}) d
}
}
fullCopy := types.CustomBool(cloneFull)
fullCopy := types2.CustomBool(cloneFull)
cloneBody := &vms.CloneRequestBody{
FullCopy: &fullCopy,
@ -1392,7 +1393,7 @@ func vmCreateClone(ctx context.Context, d *schema.ResourceData, m interface{}) d
}
// Migrate to target node
withLocalDisks := types.CustomBool(true)
withLocalDisks := types2.CustomBool(true)
migrateBody := &vms.MigrateRequestBody{
TargetNode: nodeName,
WithLocalDisks: &withLocalDisks,
@ -1426,7 +1427,7 @@ func vmCreateClone(ctx context.Context, d *schema.ResourceData, m interface{}) d
}
// Now that the virtual machine has been cloned, we need to perform some modifications.
acpi := types.CustomBool(d.Get(mkResourceVirtualEnvironmentVMACPI).(bool))
acpi := types2.CustomBool(d.Get(mkResourceVirtualEnvironmentVMACPI).(bool))
agent := d.Get(mkResourceVirtualEnvironmentVMAgent).([]interface{})
audioDevices := vmGetAudioDeviceList(d)
@ -1442,9 +1443,9 @@ func vmCreateClone(ctx context.Context, d *schema.ResourceData, m interface{}) d
networkDevice := d.Get(mkResourceVirtualEnvironmentVMNetworkDevice).([]interface{})
operatingSystem := d.Get(mkResourceVirtualEnvironmentVMOperatingSystem).([]interface{})
serialDevice := d.Get(mkResourceVirtualEnvironmentVMSerialDevice).([]interface{})
onBoot := types.CustomBool(d.Get(mkResourceVirtualEnvironmentVMOnBoot).(bool))
tabletDevice := types.CustomBool(d.Get(mkResourceVirtualEnvironmentVMTabletDevice).(bool))
template := types.CustomBool(d.Get(mkResourceVirtualEnvironmentVMTemplate).(bool))
onBoot := types2.CustomBool(d.Get(mkResourceVirtualEnvironmentVMOnBoot).(bool))
tabletDevice := types2.CustomBool(d.Get(mkResourceVirtualEnvironmentVMTabletDevice).(bool))
template := types2.CustomBool(d.Get(mkResourceVirtualEnvironmentVMTemplate).(bool))
vga := d.Get(mkResourceVirtualEnvironmentVMVGA).([]interface{})
updateBody := &vms.UpdateRequestBody{
@ -1463,10 +1464,10 @@ func vmCreateClone(ctx context.Context, d *schema.ResourceData, m interface{}) d
if len(agent) > 0 {
agentBlock := agent[0].(map[string]interface{})
agentEnabled := types.CustomBool(
agentEnabled := types2.CustomBool(
agentBlock[mkResourceVirtualEnvironmentVMAgentEnabled].(bool),
)
agentTrim := types.CustomBool(agentBlock[mkResourceVirtualEnvironmentVMAgentTrim].(bool))
agentTrim := types2.CustomBool(agentBlock[mkResourceVirtualEnvironmentVMAgentTrim].(bool))
agentType := agentBlock[mkResourceVirtualEnvironmentVMAgentType].(string)
updateBody.Agent = &vms.CustomAgent{
@ -1753,7 +1754,7 @@ func vmCreateClone(ctx context.Context, d *schema.ResourceData, m interface{}) d
)
}
deleteOriginalDisk := types.CustomBool(true)
deleteOriginalDisk := types2.CustomBool(true)
diskMoveBody := &vms.MoveDiskRequestBody{
DeleteOriginalDisk: &deleteOriginalDisk,
@ -1806,7 +1807,7 @@ func vmCreateCustom(ctx context.Context, d *schema.ResourceData, m interface{})
resource := VM()
acpi := types.CustomBool(d.Get(mkResourceVirtualEnvironmentVMACPI).(bool))
acpi := types2.CustomBool(d.Get(mkResourceVirtualEnvironmentVMACPI).(bool))
agentBlock, err := getSchemaBlock(
resource,
@ -1819,10 +1820,10 @@ func vmCreateCustom(ctx context.Context, d *schema.ResourceData, m interface{})
return diag.FromErr(err)
}
agentEnabled := types.CustomBool(
agentEnabled := types2.CustomBool(
agentBlock[mkResourceVirtualEnvironmentVMAgentEnabled].(bool),
)
agentTrim := types.CustomBool(agentBlock[mkResourceVirtualEnvironmentVMAgentTrim].(bool))
agentTrim := types2.CustomBool(agentBlock[mkResourceVirtualEnvironmentVMAgentTrim].(bool))
agentType := agentBlock[mkResourceVirtualEnvironmentVMAgentType].(string)
kvmArguments := d.Get(mkResourceVirtualEnvironmentVMKVMArguments).(string)
@ -1936,9 +1937,9 @@ func vmCreateCustom(ctx context.Context, d *schema.ResourceData, m interface{})
serialDevices := vmGetSerialDeviceList(d)
onBoot := types.CustomBool(d.Get(mkResourceVirtualEnvironmentVMOnBoot).(bool))
tabletDevice := types.CustomBool(d.Get(mkResourceVirtualEnvironmentVMTabletDevice).(bool))
template := types.CustomBool(d.Get(mkResourceVirtualEnvironmentVMTemplate).(bool))
onBoot := types2.CustomBool(d.Get(mkResourceVirtualEnvironmentVMOnBoot).(bool))
tabletDevice := types2.CustomBool(d.Get(mkResourceVirtualEnvironmentVMTabletDevice).(bool))
template := types2.CustomBool(d.Get(mkResourceVirtualEnvironmentVMTemplate).(bool))
vgaDevice, err := vmGetVGADeviceObject(d)
if err != nil {
@ -2161,8 +2162,8 @@ func vmCreateCustomDisks(ctx context.Context, d *schema.ResourceData, m interfac
size, _ := block[mkResourceVirtualEnvironmentVMDiskSize].(int)
speed := block[mkResourceVirtualEnvironmentVMDiskSpeed].([]interface{})
diskInterface, _ := block[mkResourceVirtualEnvironmentVMDiskInterface].(string)
ioThread := types.CustomBool(block[mkResourceVirtualEnvironmentVMDiskIOThread].(bool))
ssd := types.CustomBool(block[mkResourceVirtualEnvironmentVMDiskSSD].(bool))
ioThread := types2.CustomBool(block[mkResourceVirtualEnvironmentVMDiskIOThread].(bool))
ssd := types2.CustomBool(block[mkResourceVirtualEnvironmentVMDiskSSD].(bool))
discard, _ := block[mkResourceVirtualEnvironmentVMDiskDiscard].(string)
if fileFormat == "" {
@ -2510,8 +2511,8 @@ func vmGetDiskDeviceObjects(
fileID, _ := block[mkResourceVirtualEnvironmentVMDiskFileID].(string)
size, _ := block[mkResourceVirtualEnvironmentVMDiskSize].(int)
diskInterface, _ := block[mkResourceVirtualEnvironmentVMDiskInterface].(string)
ioThread := types.CustomBool(block[mkResourceVirtualEnvironmentVMDiskIOThread].(bool))
ssd := types.CustomBool(block[mkResourceVirtualEnvironmentVMDiskSSD].(bool))
ioThread := types2.CustomBool(block[mkResourceVirtualEnvironmentVMDiskIOThread].(bool))
ssd := types2.CustomBool(block[mkResourceVirtualEnvironmentVMDiskSSD].(bool))
discard := block[mkResourceVirtualEnvironmentVMDiskDiscard].(string)
speedBlock, err := getSchemaBlock(
@ -2601,12 +2602,12 @@ func vmGetHostPCIDeviceObjects(d *schema.ResourceData) vms.CustomPCIDevices {
ids, _ := block[mkResourceVirtualEnvironmentVMHostPCIDeviceID].(string)
mdev, _ := block[mkResourceVirtualEnvironmentVMHostPCIDeviceMDev].(string)
pcie := types.CustomBool(block[mkResourceVirtualEnvironmentVMHostPCIDevicePCIE].(bool))
rombar := types.CustomBool(
pcie := types2.CustomBool(block[mkResourceVirtualEnvironmentVMHostPCIDevicePCIE].(bool))
rombar := types2.CustomBool(
block[mkResourceVirtualEnvironmentVMHostPCIDeviceROMBAR].(bool),
)
romfile, _ := block[mkResourceVirtualEnvironmentVMHostPCIDeviceROMFile].(string)
xvga := types.CustomBool(block[mkResourceVirtualEnvironmentVMHostPCIDeviceXVGA].(bool))
xvga := types2.CustomBool(block[mkResourceVirtualEnvironmentVMHostPCIDeviceXVGA].(bool))
device := vms.CustomPCIDevice{
DeviceIDs: strings.Split(ids, ";"),
@ -2641,7 +2642,7 @@ func vmGetNetworkDeviceObjects(d *schema.ResourceData) vms.CustomNetworkDevices
bridge := block[mkResourceVirtualEnvironmentVMNetworkDeviceBridge].(string)
enabled := block[mkResourceVirtualEnvironmentVMNetworkDeviceEnabled].(bool)
firewall := types.CustomBool(block[mkResourceVirtualEnvironmentVMNetworkDeviceFirewall].(bool))
firewall := types2.CustomBool(block[mkResourceVirtualEnvironmentVMNetworkDeviceFirewall].(bool))
macAddress := block[mkResourceVirtualEnvironmentVMNetworkDeviceMACAddress].(string)
model := block[mkResourceVirtualEnvironmentVMNetworkDeviceModel].(string)
rateLimit := block[mkResourceVirtualEnvironmentVMNetworkDeviceRateLimit].(float64)
@ -2757,7 +2758,7 @@ func vmGetVGADeviceObject(d *schema.ResourceData) (*vms.CustomVGADevice, error)
return nil, err
}
vgaEnabled := types.CustomBool(vgaBlock[mkResourceVirtualEnvironmentVMAgentEnabled].(bool))
vgaEnabled := types2.CustomBool(vgaBlock[mkResourceVirtualEnvironmentVMAgentEnabled].(bool))
vgaMemory := vgaBlock[mkResourceVirtualEnvironmentVMVGAMemory].(int)
vgaType := vgaBlock[mkResourceVirtualEnvironmentVMVGAType].(string)
@ -4008,7 +4009,7 @@ func vmUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.D
// Prepare the new primitive configuration values.
if d.HasChange(mkResourceVirtualEnvironmentVMACPI) {
acpi := types.CustomBool(d.Get(mkResourceVirtualEnvironmentVMACPI).(bool))
acpi := types2.CustomBool(d.Get(mkResourceVirtualEnvironmentVMACPI).(bool))
updateBody.ACPI = &acpi
rebootRequired = true
}
@ -4031,7 +4032,7 @@ func vmUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.D
}
if d.HasChange(mkResourceVirtualEnvironmentVMOnBoot) {
startOnBoot := types.CustomBool(d.Get(mkResourceVirtualEnvironmentVMOnBoot).(bool))
startOnBoot := types2.CustomBool(d.Get(mkResourceVirtualEnvironmentVMOnBoot).(bool))
updateBody.StartOnBoot = &startOnBoot
}
@ -4061,12 +4062,12 @@ func vmUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.D
}
if d.HasChange(mkResourceVirtualEnvironmentVMTabletDevice) {
tabletDevice := types.CustomBool(d.Get(mkResourceVirtualEnvironmentVMTabletDevice).(bool))
tabletDevice := types2.CustomBool(d.Get(mkResourceVirtualEnvironmentVMTabletDevice).(bool))
updateBody.TabletDeviceEnabled = &tabletDevice
rebootRequired = true
}
template := types.CustomBool(d.Get(mkResourceVirtualEnvironmentVMTemplate).(bool))
template := types2.CustomBool(d.Get(mkResourceVirtualEnvironmentVMTemplate).(bool))
if d.HasChange(mkResourceVirtualEnvironmentVMTemplate) {
updateBody.Template = &template
@ -4086,10 +4087,10 @@ func vmUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.D
return diag.FromErr(err)
}
agentEnabled := types.CustomBool(
agentEnabled := types2.CustomBool(
agentBlock[mkResourceVirtualEnvironmentVMAgentEnabled].(bool),
)
agentTrim := types.CustomBool(agentBlock[mkResourceVirtualEnvironmentVMAgentTrim].(bool))
agentTrim := types2.CustomBool(agentBlock[mkResourceVirtualEnvironmentVMAgentTrim].(bool))
agentType := agentBlock[mkResourceVirtualEnvironmentVMAgentType].(string)
updateBody.Agent = &vms.CustomAgent{
@ -4436,7 +4437,7 @@ func vmUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.D
return diag.FromErr(e)
}
} else {
forceStop := types.CustomBool(true)
forceStop := types2.CustomBool(true)
shutdownTimeout := d.Get(mkResourceVirtualEnvironmentVMTimeoutShutdownVM).(int)
e = vmAPI.ShutdownVM(ctx, &vms.ShutdownRequestBody{
@ -4518,7 +4519,7 @@ func vmUpdateDiskLocationAndSize(
}
if *oldDisk.ID != *diskNewEntries[prefix][oldKey].ID {
deleteOriginalDisk := types.CustomBool(true)
deleteOriginalDisk := types2.CustomBool(true)
diskMoveBodies = append(
diskMoveBodies,
@ -4546,7 +4547,7 @@ func vmUpdateDiskLocationAndSize(
}
if shutdownForDisksRequired && !template {
forceStop := types.CustomBool(true)
forceStop := types2.CustomBool(true)
shutdownTimeout := d.Get(mkResourceVirtualEnvironmentVMTimeoutShutdownVM).(int)
err = vmAPI.ShutdownVM(
@ -4630,7 +4631,7 @@ func vmDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.D
}
if status.Status != "stopped" {
forceStop := types.CustomBool(true)
forceStop := types2.CustomBool(true)
shutdownTimeout := d.Get(mkResourceVirtualEnvironmentVMTimeoutShutdownVM).(int)
err = vmAPI.ShutdownVM(

View File

@ -5,6 +5,7 @@ go 1.20
require (
github.com/golangci/golangci-lint v1.53.3
github.com/goreleaser/goreleaser v1.18.2
github.com/hashicorp/terraform-plugin-docs v0.15.0
)
require (
@ -46,15 +47,18 @@ require (
github.com/Masterminds/semver v1.5.0 // indirect
github.com/Masterminds/semver/v3 v3.2.1 // indirect
github.com/Masterminds/sprig v2.22.0+incompatible // indirect
github.com/Masterminds/sprig/v3 v3.2.2 // indirect
github.com/Microsoft/go-winio v0.6.0 // indirect
github.com/OpenPeeDeeP/depguard/v2 v2.1.0 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20211112122917-428f8eabeeb3 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect
github.com/ProtonMail/go-mime v0.0.0-20220302105931-303f85f7fe0f // indirect
github.com/acomagu/bufpipe v1.0.3 // indirect
github.com/acomagu/bufpipe v1.0.4 // indirect
github.com/alessio/shellescape v1.4.1 // indirect
github.com/alexkohler/nakedret/v2 v2.0.2 // indirect
github.com/alexkohler/prealloc v1.0.0 // indirect
github.com/alingse/asasalint v0.0.11 // indirect
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
github.com/armon/go-radix v1.0.0 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/ashanbrown/forbidigo v1.5.3 // indirect
github.com/ashanbrown/makezero v1.1.1 // indirect
@ -85,6 +89,7 @@ require (
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20220517224237-e6f29200ae04 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bgentry/speakeasy v0.1.0 // indirect
github.com/bkielbasa/cyclop v1.2.1 // indirect
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb // indirect
github.com/blizzy78/varnamelen v0.8.0 // indirect
@ -106,6 +111,7 @@ require (
github.com/charmbracelet/lipgloss v0.7.1 // indirect
github.com/chavacava/garif v0.0.0-20230227094218-b8c73b2037b8 // indirect
github.com/chrismellard/docker-credential-acr-env v0.0.0-20220327082430-c57b701bfc08 // indirect
github.com/cloudflare/circl v1.3.3 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/curioswitch/go-reassign v0.2.0 // indirect
@ -127,7 +133,7 @@ require (
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/elliotchance/orderedmap/v2 v2.2.0 // indirect
github.com/emirpasic/gods v1.12.0 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/esimonov/ifshort v1.0.4 // indirect
github.com/ettle/strcase v0.1.1 // indirect
github.com/evanphx/json-patch/v5 v5.6.0 // indirect
@ -138,8 +144,8 @@ require (
github.com/fzipp/gocyclo v0.6.0 // indirect
github.com/go-critic/go-critic v0.8.1 // indirect
github.com/go-git/gcfg v1.5.0 // indirect
github.com/go-git/go-billy/v5 v5.3.1 // indirect
github.com/go-git/go-git/v5 v5.4.2 // indirect
github.com/go-git/go-billy/v5 v5.4.1 // indirect
github.com/go-git/go-git/v5 v5.6.1 // indirect
github.com/go-openapi/analysis v0.21.4 // indirect
github.com/go-openapi/errors v0.20.3 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
@ -195,11 +201,16 @@ require (
github.com/gostaticanalysis/forcetypeassert v0.1.0 // indirect
github.com/gostaticanalysis/nilerr v0.1.1 // 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-multierror v1.1.1 // indirect
github.com/hashicorp/go-retryablehttp v0.7.2 // indirect
github.com/hashicorp/go-uuid v1.0.3 // indirect
github.com/hashicorp/go-version v1.6.0 // indirect
github.com/hashicorp/hc-install v0.5.2 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hashicorp/terraform-exec v0.18.1 // indirect
github.com/hashicorp/terraform-json v0.16.0 // indirect
github.com/hexops/gotextdiff v1.0.3 // indirect
github.com/huandu/xstrings v1.3.2 // indirect
github.com/iancoleman/orderedmap v0.2.0 // indirect
@ -213,7 +224,7 @@ require (
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/julz/importas v0.1.0 // indirect
github.com/kevinburke/ssh_config v1.1.0 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/kisielk/errcheck v1.6.3 // indirect
github.com/kisielk/gotool v1.0.0 // indirect
github.com/kkHAIKE/contextcheck v1.1.4 // indirect
@ -241,6 +252,7 @@ require (
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mbilski/exhaustivestruct v1.2.0 // indirect
github.com/mgechev/revive v1.3.2 // indirect
github.com/mitchellh/cli v1.1.5 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
@ -263,10 +275,12 @@ require (
github.com/opencontainers/image-spec v1.1.0-rc2 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/polyfloyd/go-errorlint v1.4.2 // indirect
github.com/posener/complete v1.2.3 // indirect
github.com/prometheus/client_golang v1.15.1 // indirect
github.com/prometheus/client_model v0.4.0 // indirect
github.com/prometheus/common v0.42.0 // indirect
@ -276,6 +290,7 @@ require (
github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect
github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect
github.com/rivo/uniseg v0.4.2 // indirect
github.com/russross/blackfriday v1.6.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/ryancurrah/gomodguard v1.3.0 // indirect
github.com/ryanrolds/sqlclosecheck v0.4.0 // indirect
@ -286,6 +301,7 @@ require (
github.com/securego/gosec/v2 v2.16.0 // indirect
github.com/sergi/go-diff v1.2.0 // indirect
github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c // indirect
github.com/shopspring/decimal v1.3.1 // indirect
github.com/sigstore/cosign/v2 v2.0.0 // indirect
github.com/sigstore/rekor v1.2.0 // indirect
github.com/sigstore/sigstore v1.6.4 // indirect
@ -293,6 +309,7 @@ require (
github.com/sivchari/containedctx v1.0.3 // indirect
github.com/sivchari/nosnakecase v1.7.0 // indirect
github.com/sivchari/tenv v1.7.1 // indirect
github.com/skeema/knownhosts v1.1.0 // indirect
github.com/slack-go/slack v0.12.2 // indirect
github.com/sonatard/noctx v0.0.2 // indirect
github.com/sourcegraph/go-diff v0.7.0 // indirect
@ -325,11 +342,12 @@ require (
github.com/vbatts/tar-split v0.11.2 // indirect
github.com/withfig/autocomplete-tools/integrations/cobra v1.2.1 // indirect
github.com/xanzy/go-gitlab v0.83.0 // indirect
github.com/xanzy/ssh-agent v0.3.1 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/xen0n/gosmopolitan v1.2.1 // indirect
github.com/yagipy/maintidx v1.0.0 // indirect
github.com/yeya24/promlinter v0.2.0 // indirect
github.com/ykadowak/zerologlint v0.1.2 // indirect
github.com/zclconf/go-cty v1.13.2 // indirect
gitlab.com/bosi/decorder v0.2.3 // indirect
gitlab.com/digitalxero/go-conventional-commit v1.0.7 // indirect
go.mongodb.org/mongo-driver v1.11.3 // indirect

View File

@ -535,6 +535,9 @@ 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 v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60=
github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
github.com/Masterminds/sprig/v3 v3.2.1/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk=
github.com/Masterminds/sprig/v3 v3.2.2 h1:17jRggJu518dr3QaafizSXOjKYp94wKfABxUmyxvxX8=
github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk=
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
@ -543,8 +546,8 @@ github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugX
github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg=
github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE=
github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
@ -566,9 +569,8 @@ github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEV
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/OpenPeeDeeP/depguard/v2 v2.1.0 h1:aQl70G173h/GZYhWf36aE5H0KaujXfVMnn/f1kSDVYY=
github.com/OpenPeeDeeP/depguard/v2 v2.1.0/go.mod h1:PUBgk35fX4i7JDmwzlJwJ+GMe6NfO1723wmJMgPThNQ=
github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
github.com/ProtonMail/go-crypto v0.0.0-20211112122917-428f8eabeeb3 h1:XcF0cTDJeiuZ5NU8w7WUDge0HRwwNRmxj/GGk6KSA6g=
github.com/ProtonMail/go-crypto v0.0.0-20211112122917-428f8eabeeb3/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 h1:wPbRQzjjwFc0ih8puEVAOFGELsn1zoIIYdxvML7mDxA=
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g=
github.com/ProtonMail/go-mime v0.0.0-20220302105931-303f85f7fe0f h1:CGq7OieOz3wyQJ1fO8S0eO9TCW1JyvLrf8fhzz1i8ko=
github.com/ProtonMail/go-mime v0.0.0-20220302105931-303f85f7fe0f/go.mod h1:NYt+V3/4rEeDuaev/zw1zCq8uqVEuPHzDPo3OZrlGJ4=
github.com/ProtonMail/gopenpgp/v2 v2.2.2 h1:u2m7xt+CZWj88qK1UUNBoXeJCFJwJCZ/Ff4ymGoxEXs=
@ -580,8 +582,8 @@ github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:H
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk=
github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ=
github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
@ -600,9 +602,11 @@ github.com/alexkohler/prealloc v1.0.0 h1:Hbq0/3fJPQhNkN0dR95AVrr6R7tou91y0uHG5pO
github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE=
github.com/alingse/asasalint v0.0.11 h1:SFwnQXJ49Kx/1GghOFz1XGqHYKp21Kq1nHad/0WQRnw=
github.com/alingse/asasalint v0.0.11/go.mod h1:nCaoMhw7a9kSJObvQyVzNTPBDbNpdocqrSP7t/cW5+I=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
@ -610,6 +614,7 @@ github.com/armon/go-metrics v0.3.3/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4
github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI=
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
@ -726,6 +731,7 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
@ -755,6 +761,7 @@ github.com/butuzov/ireturn v0.2.0 h1:kCHi+YzC150GE98WFuZQu9yrTn6GEydO2AuPLbTgnO4
github.com/butuzov/ireturn v0.2.0/go.mod h1:Wh6Zl3IMtTpaIKbmwzqi6olnM9ptYQxxVacMsOEFPoc=
github.com/butuzov/mirror v1.1.0 h1:ZqX54gBVMXu78QLoiqdwpl2mgmoOJTk7s4p4o+0avZI=
github.com/butuzov/mirror v1.1.0/go.mod h1:8Q0BdQU6rC6WILDiBM60DBfvV78OLJmMmixe7GF45AE=
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/caarlos0/ctrlc v1.2.0 h1:AtbThhmbeYx1WW3WXdWrd94EHKi+0NPRGS4/4pzrjwk=
github.com/caarlos0/ctrlc v1.2.0/go.mod h1:n3gDlSjsXZ7rbD9/RprIR040b7oaLfNStikPd4gFago=
github.com/caarlos0/env/v8 v8.0.0 h1:POhxHhSpuxrLMIdvTGARuZqR4Jjm8AYmoi/JKlcScs0=
@ -816,6 +823,9 @@ github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6D
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I=
github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs=
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
@ -1049,8 +1059,8 @@ github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@ -1091,7 +1101,6 @@ github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSw
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/firefart/nonamedreturns v1.0.4 h1:abzI1p7mAEPYuR4A+VLKn4eNDOycjYo2phmY9sfv40Y=
github.com/firefart/nonamedreturns v1.0.4/go.mod h1:TDhe/tjI1BXo48CmYbUduTV7BdIga8MAO/xbKdcVsGI=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
@ -1118,19 +1127,19 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U=
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4=
github.com/go-critic/go-critic v0.8.1 h1:16omCF1gN3gTzt4j4J6fKI/HnRojhEp+Eks6EuKw3vw=
github.com/go-critic/go-critic v0.8.1/go.mod h1:kpzXl09SIJX1cr9TB/g/sAG+eFEl7ZS9f9cqvZtyNl0=
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34=
github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
github.com/go-git/go-git-fixtures/v4 v4.2.1 h1:n9gGL1Ct/yIw+nfsfr8s4+sbhT+Ncu2SubfXjIWgci8=
github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0=
github.com/go-git/go-git/v5 v5.4.2 h1:BXyZu9t0VkbiHtqrsvdq39UDhGJTl1h55VW6CSC4aY4=
github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc=
github.com/go-git/go-billy/v5 v5.4.1 h1:Uwp5tDRkPr+l/TnbHOQzp+tmJfLceOlbVucgpTz8ix4=
github.com/go-git/go-billy/v5 v5.4.1/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw45YK/ukIvQg=
github.com/go-git/go-git-fixtures/v4 v4.3.1 h1:y5z6dd3qi8Hl+stezc8p3JxDkoTRqMAlKnXHuzrfjTQ=
github.com/go-git/go-git-fixtures/v4 v4.3.1/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo=
github.com/go-git/go-git/v5 v5.6.1 h1:q4ZRqQl4pR/ZJHc1L5CFjGA1a10u76aV1iC+nh+bHsk=
github.com/go-git/go-git/v5 v5.6.1/go.mod h1:mvyoL6Unz0PiTQrGQfSfiLFhBH1c1e84ylC2MDs4ee8=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@ -1535,6 +1544,8 @@ github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FK
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=
github.com/hashicorp/go-checkpoint v0.5.0 h1:MFYpPZCnQqQTE18jFwSII6eUQrD/oxMFp3mlgcqk5mU=
github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuDrwkBuEQsVcpCOgg=
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
@ -1566,6 +1577,8 @@ github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdv
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
@ -1574,6 +1587,8 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/golang-lru v0.6.0/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/hc-install v0.5.2 h1:SfwMFnEXVVirpwkDuSF5kymUOhrUxrTq3udEseZdOD0=
github.com/hashicorp/hc-install v0.5.2/go.mod h1:9QISwe6newMWIfEiXpzuu1k9HAGtQYgnSH8H9T8wmoI=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
@ -1591,6 +1606,12 @@ github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKEN
github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=
github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=
github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4=
github.com/hashicorp/terraform-exec v0.18.1 h1:LAbfDvNQU1l0NOQlTuudjczVhHj061fNX5H8XZxHlH4=
github.com/hashicorp/terraform-exec v0.18.1/go.mod h1:58wg4IeuAJ6LVsLUeD2DWZZoc/bYi6dzhLHzxM41980=
github.com/hashicorp/terraform-json v0.16.0 h1:UKkeWRWb23do5LNAFlh/K3N0ymn1qTOO8c+85Albo3s=
github.com/hashicorp/terraform-json v0.16.0/go.mod h1:v0Ufk9jJnk6tcIZvScHvetlKfiNTC+WS21mnXIlc0B0=
github.com/hashicorp/terraform-plugin-docs v0.15.0 h1:W5xYB5kCUBqO7lyjE2UMmUBh95c0aAf4jwO0Xuuw2Ec=
github.com/hashicorp/terraform-plugin-docs v0.15.0/go.mod h1:K5Taof1Y7sL4dw6Ie0qMFyQnHN0W+RSVMD0iIyFDFJc=
github.com/hetznercloud/hcloud-go v1.33.1/go.mod h1:XX/TQub3ge0yWR2yHWmnDVIrB+MQbda1pHxkUmDlUME=
github.com/hetznercloud/hcloud-go v1.39.0/go.mod h1:mepQwR6va27S3UQthaEPGS86jtzSY9xWL1e9dyxXpgA=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
@ -1598,6 +1619,7 @@ github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSo
github.com/honeycombio/beeline-go v1.10.0 h1:cUDe555oqvw8oD76BQJ8alk7FP0JZ/M/zXpNvOEDLDc=
github.com/honeycombio/libhoney-go v1.16.0 h1:kPpqoz6vbOzgp7jC6SR7SkNj7rua7rgxvznI6M3KdHc=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/hudl/fargo v1.4.0/go.mod h1:9Ai6uvFy5fQNq6VPKtg+Ceq1+eTY4nKUlR2JElEOcDo=
@ -1615,6 +1637,7 @@ github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ
github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM=
github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
@ -1713,9 +1736,8 @@ github.com/julz/importas v0.1.0/go.mod h1:oSFU2R4XK/P7kNBrnL/FEQlDGN1/6WoxXEjSSX
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4=
github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/kevinburke/ssh_config v1.1.0 h1:pH/t1WS9NzT8go394IqZeJTMHVm6Cr6ZJ6AQ+mdNo/o=
github.com/kevinburke/ssh_config v1.1.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
@ -1865,6 +1887,9 @@ github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLT
github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
github.com/mitchellh/cli v1.1.5 h1:OxRIeJXpAMztws/XHlN2vu6imG5Dpq+j61AzAX5fLng=
github.com/mitchellh/cli v1.1.5/go.mod h1:v8+iFts2sPIKUV1ltktPXMCC8fumSKFItNcD2cLtRR4=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
@ -1884,8 +1909,10 @@ github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/mmcloughlin/avo v0.5.0/go.mod h1:ChHFdoV7ql95Wi7vuq2YT1bwCJqiWdZrQ1im3VujLYM=
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
@ -2052,6 +2079,8 @@ github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha
github.com/performancecopilot/speed/v4 v4.0.0/go.mod h1:qxrSyuDGrTOWfV+uKRFhfxw6h/4HXRGUiZiufxo49BM=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
@ -2069,6 +2098,7 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/polyfloyd/go-errorlint v1.4.2 h1:CU+O4181IxFDdPH6t/HT7IiDj1I7zxNi1RIUxYwn8d0=
github.com/polyfloyd/go-errorlint v1.4.2/go.mod h1:k6fU/+fQe38ednoZS51T7gSIGQW1y94d6TkSr35OzH8=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo=
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
@ -2163,6 +2193,8 @@ github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww=
github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@ -2201,6 +2233,8 @@ github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAx
github.com/shoenig/test v0.6.0/go.mod h1:xYtyGBC5Q3kzCNyJg/SjgNpfAa2kvmgA0i5+lQso8x0=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
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/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
@ -2229,6 +2263,8 @@ github.com/sivchari/nosnakecase v1.7.0 h1:7QkpWIRMe8x25gckkFd2A5Pi6Ymo0qgr4JrhGt
github.com/sivchari/nosnakecase v1.7.0/go.mod h1:CwDzrzPea40/GB6uynrNLiorAlgFRvRbFSgJx2Gs+QY=
github.com/sivchari/tenv v1.7.1 h1:PSpuD4bu6fSmtWMxSGWcvqUUgIn7k3yOJhOIzVWn8Ak=
github.com/sivchari/tenv v1.7.1/go.mod h1:64yStXKSOxDfX47NlhVwND4dHwfZDdbp2Lyl018Icvg=
github.com/skeema/knownhosts v1.1.0 h1:Wvr9V0MxhjRbl3f9nMnKnFfiWTJmtECJ9Njkea3ysW0=
github.com/skeema/knownhosts v1.1.0/go.mod h1:sKFq3RD6/TKZkSWn8boUbDC7Qkgcv+8XXijpFO6roag=
github.com/slack-go/slack v0.12.2 h1:x3OppyMyGIbbiyFhsBmpf9pwkUzMhthJMRNmNlA4LaQ=
github.com/slack-go/slack v0.12.2/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
@ -2386,9 +2422,8 @@ github.com/withfig/autocomplete-tools/integrations/cobra v1.2.1 h1:+dBg5k7nuTE38
github.com/withfig/autocomplete-tools/integrations/cobra v1.2.1/go.mod h1:nmuySobZb4kFgFy6BptpXp/BBw+xFSyvVPP6auoJB4k=
github.com/xanzy/go-gitlab v0.83.0 h1:37p0MpTPNbsTMKX/JnmJtY8Ch1sFiJzVF342+RvZEGw=
github.com/xanzy/go-gitlab v0.83.0/go.mod h1:5ryv+MnpZStBH8I/77HuQBsMbBGANtVpLWC15qOjWAw=
github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
github.com/xanzy/ssh-agent v0.3.1 h1:AmzO1SSWxw73zxFZPRwaMN1MohDw8UyHnmuxyceTEGo=
github.com/xanzy/ssh-agent v0.3.1/go.mod h1:QIE4lCeL7nkC25x+yA3LBIYfwCc1TFziCtG7cBAac6w=
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
@ -2423,6 +2458,8 @@ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5t
github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
github.com/zclconf/go-cty v1.13.2 h1:4GvrUxe/QUDYuJKAav4EYqdM47/kZa672LwmXFmEKT0=
github.com/zclconf/go-cty v1.13.2/go.mod h1:YKQzy/7pZ7iq2jNFzy5go57xdxdWoLLpaEp4u238AE0=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
gitlab.com/bosi/decorder v0.2.3 h1:gX4/RgK16ijY8V+BRQHAySfQAb354T7/xQpDB2n10P0=
gitlab.com/bosi/decorder v0.2.3/go.mod h1:9K1RB5+VPNQYtXtTDAzd2OEftsZb1oV0IrJrzChSdGE=
@ -2546,11 +2583,11 @@ go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
gocloud.dev v0.29.0 h1:fBy0jwJSmxs0IjT0fE32MO+Mj+307VZQwyHaTyFZbC4=
gocloud.dev v0.29.0/go.mod h1:E3dAjji80g+lIkq4CQeF/BTWqv1CBeTftmOb+gpyapQ=
golang.org/x/arch v0.1.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
@ -2563,8 +2600,10 @@ golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
@ -2584,8 +2623,10 @@ golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0
golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220511200225-c6db032c6c88/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20221012134737-56aed061732a/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
@ -2699,7 +2740,6 @@ golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
@ -2727,6 +2767,7 @@ golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220805013720-a33c5aa5df48/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.0.0-20220921155015-db77216a4ee9/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
@ -2738,6 +2779,7 @@ golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10/go.mod h1:MBQ8lrhLObU/6UmL
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@ -2890,7 +2932,6 @@ golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210503080704-8803ae5d1324/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -2940,6 +2981,7 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -2954,6 +2996,7 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
@ -3436,6 +3479,7 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=

View File

@ -1,6 +1,12 @@
//go:build tools
// +build tools
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package tools
// Manage tool dependencies via go.mod.
@ -10,4 +16,5 @@ package tools
import (
_ "github.com/golangci/golangci-lint/cmd/golangci-lint"
_ "github.com/goreleaser/goreleaser"
_ "github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs"
)

34
utils/env.go Normal file
View File

@ -0,0 +1,34 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package utils
import "os"
// GetAnyStringEnv returns the first non-empty string value from the environment variables.
func GetAnyStringEnv(ks ...string) string {
for _, k := range ks {
if v := os.Getenv(k); v != "" {
return v
}
}
return ""
}
// GetAnyBoolEnv returns the first non-empty boolean value from the environment variables.
func GetAnyBoolEnv(ks ...string) bool {
val := ""
for _, k := range ks {
if v := os.Getenv(k); v != "" {
val = v
break
}
}
return val == "true" || val == "1"
}