0
0
mirror of https://github.com/bpg/terraform-provider-proxmox.git synced 2025-06-30 02:31: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

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"
}